@@ -23,6 +23,12 @@ class ByteFormatter
2323 /** @var int */
2424 private $ precision = 0 ;
2525
26+ /** @var bool */
27+ private $ automaticPrecision = true ;
28+
29+ /** @var int */
30+ private $ exponent ;
31+
2632 /** @var UnitDecorator */
2733 private $ unitDecorator ;
2834
@@ -51,14 +57,48 @@ public function __construct(UnitDecorator $unitDecorator = null)
5157 public function format ($ bytes , $ precision = null )
5258 {
5359 // Use default precision when not specified.
54- $ precision === null && $ precision = $ this ->precision ;
60+ $ precision === null && $ precision = $ this ->getPrecision ();
61+
62+ $ log = log ($ bytes , $ this ->getBase ());
63+ $ exponent = $ this ->hasFixedExponent () ? $ this ->getFixedExponent () : max (0 , $ log |0 );
64+ $ value = round (pow ($ this ->getBase (), $ log - $ exponent ), $ precision );
65+ $ units = $ this ->getUnitDecorator ()->decorate ($ exponent , $ this ->getBase (), $ value );
66+
67+ return trim (sprintf ($ this ->sprintfFormat , $ this ->formatValue ($ value , $ precision ), $ units ));
68+ }
69+
70+ /**
71+ * Formats the specified number with the specified precision.
72+ *
73+ * If precision scaling is enabled the precision may be reduced when it
74+ * contains non-significant digits. If the fractional part is zero it may
75+ * be removed entirely.
76+ *
77+ * @param float $value Number.
78+ * @param $precision Number of fractional digits.
79+ *
80+ * @return string Formatted number.
81+ */
82+ private function formatValue ($ value , $ precision )
83+ {
84+ $ formatted = sprintf ("%0. $ {precision}F " , $ value );
85+
86+ if ($ this ->hasAutomaticPrecision ()) {
87+ // [0 => integer part, 1 => fractional part].
88+ $ formattedParts = explode ('. ' , $ formatted );
5589
56- $ log = log ($ bytes , $ this ->base );
57- $ exponent = max (0 , $ log |0 );
58- $ value = round (pow ($ this ->base , $ log - $ exponent ), $ precision );
59- $ units = $ this ->getUnitDecorator ()->decorate ($ exponent , $ this ->base , $ value );
90+ if (isset ($ formattedParts [1 ])) {
91+ // Strip trailing 0s in fractional part.
92+ if (!$ formattedParts [1 ] = chop ($ formattedParts [1 ], '0 ' )) {
93+ // Remove fractional part.
94+ unset($ formattedParts [1 ]);
95+ }
6096
61- return trim (sprintf ($ this ->sprintfFormat , $ value , $ units ));
97+ $ formatted = join ('. ' , $ formattedParts );
98+ }
99+ }
100+
101+ return $ formatted ;
62102 }
63103
64104 /**
@@ -146,6 +186,87 @@ public function setPrecision($precision)
146186 return $ this ;
147187 }
148188
189+ /**
190+ * Enables automatic precision scaling.
191+ *
192+ * @return $this
193+ */
194+ public function enableAutomaticPrecision ()
195+ {
196+ $ this ->automaticPrecision = true ;
197+
198+ return $ this ;
199+ }
200+
201+ /**
202+ * Disables automatic precision scaling.
203+ *
204+ * @return $this
205+ */
206+ public function disableAutomaticPrecision ()
207+ {
208+ $ this ->automaticPrecision = false ;
209+
210+ return $ this ;
211+ }
212+
213+ /**
214+ * Gets a value indicating whether precision will be scaled automatically.
215+ *
216+ * @return bool True if precision will be scaled automatically, otherwise
217+ * false.
218+ */
219+ public function hasAutomaticPrecision ()
220+ {
221+ return $ this ->automaticPrecision ;
222+ }
223+
224+ /**
225+ * Gets the fixed exponent.
226+ *
227+ * @return int Fixed exponent.
228+ */
229+ public function getFixedExponent ()
230+ {
231+ return $ this ->exponent ;
232+ }
233+
234+ /**
235+ * Sets the fixed exponent.
236+ *
237+ * @param int $exponent Fixed exponent.
238+ *
239+ * @return $this
240+ */
241+ public function setFixedExponent ($ exponent )
242+ {
243+ $ this ->exponent = $ exponent |0 ;
244+
245+ return $ this ;
246+ }
247+
248+ /**
249+ * Clears any fixed exponent.
250+ *
251+ * @return $this
252+ */
253+ public function clearFixedExponent ()
254+ {
255+ $ this ->exponent = null ;
256+
257+ return $ this ;
258+ }
259+
260+ /**
261+ * Gets a value indicating whether a fixed exponent has been set.
262+ *
263+ * @return bool True if a fixed exponent has been set, otherwise false.
264+ */
265+ public function hasFixedExponent ()
266+ {
267+ return $ this ->exponent !== null ;
268+ }
269+
149270 /**
150271 * Gets the unit decorator.
151272 *
0 commit comments