Total Complexity | 68 |
Total Lines | 433 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like AdminPageFramework_Debug_Base often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use AdminPageFramework_Debug_Base, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
19 | class AdminPageFramework_Debug_Base extends AdminPageFramework_FrameworkUtility { |
||
20 | |||
21 | /** |
||
22 | * @var int |
||
23 | * @since 3.8.19 |
||
24 | */ |
||
25 | static public $iLegibleArrayDepthLimit = 50; |
||
26 | |||
27 | /** |
||
28 | * Character length limit to truncate. |
||
29 | */ |
||
30 | static public $iLegibleStringCharacterLimit = 99999; |
||
31 | |||
32 | /** |
||
33 | * Returns a legible value representation with value details. |
||
34 | * @param mixed $mValue |
||
35 | * @param integer $iStringLengthLimit |
||
36 | * @param integer $iArrayDepthLimit |
||
37 | * @return string |
||
38 | * @since 3.8.9 |
||
39 | */ |
||
40 | static protected function _getLegibleDetails( $mValue, $iStringLengthLimit=0, $iArrayDepthLimit=0 ) { |
||
41 | if ( is_array( $mValue ) ) { |
||
42 | return '(array, length: ' . count( $mValue ).') ' |
||
43 | . print_r( self::___getLegibleDetailedArray( $mValue, $iStringLengthLimit, $iArrayDepthLimit ) , true ); |
||
|
|||
44 | } |
||
45 | return print_r( self::getLegibleDetailedValue( $mValue, $iStringLengthLimit ), true ); |
||
46 | } |
||
47 | |||
48 | /** |
||
49 | * Returns a object name if it is an object. Otherwise, the value itself. |
||
50 | * This is used to convert objects into a string in array-walk functions |
||
51 | * as objects tent to get large when they are converted to a string representation. |
||
52 | * @since 3.8.9 |
||
53 | * @since 3.8.32 Changed the visibility scope to public from private to be passed as a callback for outside the current class scope. |
||
54 | * And renamed from `___getObjectName()`. |
||
55 | * @param mixed $mItem |
||
56 | * @return mixed |
||
57 | */ |
||
58 | static public function getObjectName( $mItem ) { |
||
59 | if ( is_object( $mItem ) ) { |
||
60 | return '(object) ' . get_class( $mItem ); |
||
61 | } |
||
62 | return $mItem; |
||
63 | } |
||
64 | |||
65 | /** |
||
66 | * Returns a string representation of the given value with no variable details. |
||
67 | * |
||
68 | * @param $mValue |
||
69 | * @param integer $iStringLengthLimit |
||
70 | * @param integer $iArrayDepthLimit |
||
71 | * @return string |
||
72 | * @since 3.8.9 |
||
73 | * @since 3.8.22 Added the `$sStringLengthLimit` and `$iArrayDepthLimit` parameters. |
||
74 | */ |
||
75 | static protected function _getLegible( $mValue, $iStringLengthLimit=0, $iArrayDepthLimit=0 ) { |
||
76 | |||
77 | $iArrayDepthLimit = $iArrayDepthLimit ? $iArrayDepthLimit : self::$iLegibleArrayDepthLimit; |
||
78 | $mValue = is_object( $mValue ) |
||
79 | ? ( method_exists( $mValue, '__toString' ) |
||
80 | ? ( string ) $mValue // cast string |
||
81 | : ( array ) $mValue // cast array |
||
82 | ) |
||
83 | : $mValue; |
||
84 | $mValue = is_array( $mValue ) |
||
85 | ? self::getArrayMappedRecursive( |
||
86 | array( __CLASS__, 'getObjectName' ), |
||
87 | self::_getSlicedByDepth( $mValue, $iArrayDepthLimit ), |
||
88 | array() |
||
89 | ) |
||
90 | : $mValue; |
||
91 | $mValue = is_string( $mValue ) |
||
92 | ? self::___getLegibleString( $mValue, $iStringLengthLimit, false ) |
||
93 | : $mValue; |
||
94 | return self::_getArrayRepresentationSanitized( print_r( $mValue, true ) ); |
||
95 | |||
96 | } |
||
97 | |||
98 | /** |
||
99 | * @since 3.8.9 |
||
100 | * @param callable $asoCallable |
||
101 | * @return string |
||
102 | */ |
||
103 | static private function ___getLegibleDetailedCallable( $asoCallable ) { |
||
104 | return '(callable) ' . self::___getCallableName( $asoCallable ); |
||
105 | } |
||
106 | /** |
||
107 | * @since 3.8.9 |
||
108 | * @param callable $asoCallable |
||
109 | * @return string |
||
110 | */ |
||
111 | static public function ___getCallableName( $asoCallable ) { |
||
112 | |||
113 | if ( is_string( $asoCallable ) ) { |
||
114 | return $asoCallable; |
||
115 | } |
||
116 | if ( is_object( $asoCallable ) ) { |
||
117 | return get_class( $asoCallable ); |
||
118 | } |
||
119 | $_sSubject = is_object( $asoCallable[ 0 ] ) |
||
120 | ? get_class( $asoCallable[ 0 ] ) |
||
121 | : ( string ) $asoCallable[ 0 ]; |
||
122 | return $_sSubject . '::' . ( string ) $asoCallable[ 1 ]; |
||
123 | |||
124 | } |
||
125 | |||
126 | /** |
||
127 | * @since 3.8.9 |
||
128 | * @param object $oObject |
||
129 | * @return string |
||
130 | */ |
||
131 | static private function ___getLegibleDetailedObject( $oObject ) { |
||
132 | |||
133 | if ( method_exists( $oObject, '__toString' ) ) { |
||
134 | return ( string ) $oObject; |
||
135 | } |
||
136 | return '(object) ' . get_class( $oObject ) . ' ' . count( get_object_vars( $oObject ) ) . ' properties.'; |
||
137 | |||
138 | } |
||
139 | |||
140 | /** |
||
141 | * Returns an array representation with value types in each element. |
||
142 | * The element deeper than 10 dimensions will be dropped. |
||
143 | * @param array $aArray |
||
144 | * @param integer $iStringLengthLimit |
||
145 | * @param integer $iDepthLimit |
||
146 | * @return array |
||
147 | * @since 3.8.9 |
||
148 | * @since 3.8.22 Added the `$iDepthLimit` parameter |
||
149 | * @since 3.8.22 Changed the scope to private from public. |
||
150 | * @since 3.8.22 Renamed from `_getLegibleArray()`. |
||
151 | */ |
||
152 | static private function ___getLegibleDetailedArray( array $aArray, $iStringLengthLimit=0, $iDepthLimit=0 ) { |
||
153 | $_iDepthLimit = $iDepthLimit ? $iDepthLimit : self::$iLegibleArrayDepthLimit; |
||
154 | return self::getArrayMappedRecursive( |
||
155 | array( __CLASS__, 'getLegibleDetailedValue' ), |
||
156 | self::_getSlicedByDepth( $aArray, $_iDepthLimit ), |
||
157 | array( $iStringLengthLimit ) |
||
158 | ); |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * @param mixed $mItem |
||
163 | * @param integer $iStringLengthLimit |
||
164 | * @return string |
||
165 | * @since 3.8.22 Renamed from `_getLegibleValue()`. |
||
166 | * @since 3.8.9 |
||
167 | * @since 3.8.32 Changed the visibility scope to public from private to be passed as a callback for outside the current class scope. |
||
168 | * And renamed from `___getLegibleDetailedValue()`. |
||
169 | */ |
||
170 | static public function getLegibleDetailedValue( $mItem, $iStringLengthLimit ) { |
||
171 | if ( is_callable( $mItem ) ) { |
||
172 | return self::___getLegibleDetailedCallable( $mItem ); |
||
173 | } |
||
174 | return is_scalar( $mItem ) |
||
175 | ? self::___getLegibleDetailedScalar( $mItem, $iStringLengthLimit ) |
||
176 | : self::___getLegibleDetailedNonScalar( $mItem ); |
||
177 | } |
||
178 | /** |
||
179 | * @since 3.8.9 |
||
180 | * @since 3.8.22 Renamed from `_getLegibleNonScalar()`. |
||
181 | * @return string |
||
182 | * @param mixed $mNonScalar |
||
183 | */ |
||
184 | static private function ___getLegibleDetailedNonScalar( $mNonScalar ) { |
||
185 | |||
186 | $_sType = gettype( $mNonScalar ); |
||
187 | if ( is_null( $mNonScalar ) ) { |
||
188 | return '(null)'; |
||
189 | } |
||
190 | if ( is_object( $mNonScalar ) ) { |
||
191 | return self::___getLegibleDetailedObject( $mNonScalar ); |
||
192 | } |
||
193 | if ( is_array( $mNonScalar ) ) { |
||
194 | return '(' . $_sType . ') ' . count( $mNonScalar ) . ' elements'; |
||
195 | } |
||
196 | return '(' . $_sType . ') ' . ( string ) $mNonScalar; |
||
197 | |||
198 | } |
||
199 | /** |
||
200 | * @return string |
||
201 | * @param integer|float|boolean $sScalar |
||
202 | * @param integer $iStringLengthLimit |
||
203 | * @since 3.8.9 |
||
204 | * @since 3.8.22 Renamed from `_getLegibleScalar()`. |
||
205 | */ |
||
206 | static private function ___getLegibleDetailedScalar( $sScalar, $iStringLengthLimit ) { |
||
207 | if ( is_bool( $sScalar ) ) { |
||
208 | return '(boolean) ' . ( $sScalar ? 'true' : 'false' ); |
||
209 | } |
||
210 | return is_string( $sScalar ) |
||
211 | ? self::___getLegibleString( $sScalar, $iStringLengthLimit, true ) |
||
212 | : '(' . gettype( $sScalar ) . ', length: ' . self::___getValueLength( $sScalar ) . ') ' . $sScalar; |
||
213 | } |
||
214 | /** |
||
215 | * Returns a length of a value. |
||
216 | * @since 3.5.3 |
||
217 | * @internal |
||
218 | * @return integer|null For string or integer, the string length. For array, the element lengths. For other types, null. |
||
219 | * @param mixed $mValue |
||
220 | */ |
||
221 | static private function ___getValueLength( $mValue ) { |
||
222 | $_sVariableType = gettype( $mValue ); |
||
223 | if ( in_array( $_sVariableType, array( 'string', 'integer' ) ) ) { |
||
224 | return strlen( $mValue ); |
||
225 | } |
||
226 | if ( 'array' === $_sVariableType ) { |
||
227 | return count( $mValue ); |
||
228 | } |
||
229 | return null; |
||
230 | } |
||
231 | /** |
||
232 | * @param string $sString |
||
233 | * @param integer $iLengthLimit |
||
234 | * @param boolean $bShowDetails |
||
235 | * @return string |
||
236 | */ |
||
237 | static private function ___getLegibleString( $sString, $iLengthLimit, $bShowDetails=true ) { |
||
238 | |||
239 | static $_iMBSupport; |
||
240 | $_iMBSupport = isset( $_iMBSupport ) ? $_iMBSupport : ( integer ) function_exists( 'mb_strlen' ); |
||
241 | $_aStrLenMethod = array( 'strlen', 'mb_strlen' ); |
||
242 | $_aSubstrMethod = array( 'substr', 'mb_substr' ); |
||
243 | $iCharLimit = $iLengthLimit ? $iLengthLimit : self::$iLegibleStringCharacterLimit; |
||
244 | $_iCharLength = call_user_func_array( $_aStrLenMethod[ $_iMBSupport ], array( $sString ) ); |
||
245 | |||
246 | if ( $bShowDetails ) { |
||
247 | return $_iCharLength <= $iCharLimit |
||
248 | ? '(string, length: ' . $_iCharLength . ') ' . $sString |
||
249 | : '(string, length: ' . $_iCharLength . ') ' . call_user_func_array( $_aSubstrMethod[ $_iMBSupport ], array( $sString, 0, $iCharLimit ) ) |
||
250 | . '...'; |
||
251 | } |
||
252 | return $_iCharLength <= $iCharLimit |
||
253 | ? $sString |
||
254 | : call_user_func_array( $_aSubstrMethod[ $_iMBSupport ], array( $sString, 0, $iCharLimit ) ); |
||
255 | |||
256 | } |
||
257 | |||
258 | /** |
||
259 | * @return string |
||
260 | * @since 3.8.9 |
||
261 | * @param string $sString |
||
262 | */ |
||
263 | static protected function _getArrayRepresentationSanitized( $sString ) { |
||
279 | |||
280 | } |
||
281 | |||
282 | /** |
||
283 | * Slices an array by the given depth. |
||
284 | * @param array $aSubject |
||
285 | * @param int $iDepth |
||
286 | * @param string $sMore |
||
287 | * @return array |
||
288 | * @since 3.8.22 |
||
289 | */ |
||
290 | static public function getSlicedByDepth( array $aSubject, $iDepth=0, $sMore='(array truncated) ...' ) { |
||
291 | return self::_getSlicedByDepth( $aSubject, $iDepth, $sMore ); |
||
292 | } |
||
293 | |||
294 | /** |
||
295 | * Slices an array by the given depth. |
||
296 | * |
||
297 | * @param array $aSubject |
||
298 | * @param int $iDepth |
||
299 | * @param string $sMore |
||
300 | * |
||
301 | * @return array |
||
302 | * @since 3.4.4 |
||
303 | * @since 3.8.9 Changed it not to convert an object into an array. |
||
304 | * @since 3.8.9 Changed the scope to private. |
||
305 | * @since 3.8.9 Renamed from `getSliceByDepth()`. |
||
306 | * @since 3.8.22 Show a message when truncated by depth. |
||
307 | * @since 3.8.22 Added the `$sMore` parameter. |
||
308 | * @internal |
||
309 | */ |
||
310 | static private function _getSlicedByDepth( array $aSubject, $iDepth=0, $sMore='(array truncated) ...' ) { |
||
333 | |||
334 | } |
||
335 | |||
336 | /** |
||
337 | * @param integer $iSkip The number of skipping records. This is used when the caller does not want to include the self function/method. |
||
338 | * @param null $_deprecated |
||
339 | * @return string |
||
340 | * @since 3.8.22 |
||
341 | * @since 3.8.23 Deprecated the `$oException` parameter. |
||
342 | */ |
||
343 | static public function getStackTrace( $iSkip=0, $_deprecated=null ) { |
||
344 | |||
345 | $_iSkip = 1; // need to skip this method trace itself |
||
346 | $_oException = new Exception(); |
||
347 | |||
348 | // Backward compatibility. |
||
349 | if ( is_object( $iSkip ) && $iSkip instanceof Exception ) { |
||
350 | $_oException = $iSkip; |
||
351 | $iSkip = ( integer ) $_deprecated; |
||
352 | } |
||
353 | |||
354 | $_iSkip = $_iSkip + $iSkip; |
||
355 | |||
356 | $_aTraces = array(); |
||
357 | $_aFrames = $_oException->getTrace(); |
||
358 | $_aFrames = array_slice( $_aFrames, $_iSkip ); |
||
359 | foreach ( array_reverse( $_aFrames ) as $_iIndex => $_aFrame ) { |
||
360 | |||
361 | $_aFrame = $_aFrame + array( |
||
362 | 'file' => null, 'line' => null, 'function' => null, |
||
363 | 'class' => null, 'args' => array(), |
||
364 | ); |
||
365 | $_sArguments = self::___getArgumentsOfEachStackTrace( $_aFrame[ 'args' ] ); |
||
366 | $_aTraces[] = sprintf( |
||
367 | "#%s %s(%s): %s(%s)", |
||
368 | $_iIndex + 1, |
||
369 | $_aFrame[ 'file' ], |
||
370 | $_aFrame[ 'line' ], |
||
371 | isset( $_aFrame[ 'class' ] ) ? $_aFrame[ 'class' ] . '->' . $_aFrame[ 'function' ] : $_aFrame[ 'function' ], |
||
372 | $_sArguments |
||
373 | ); |
||
374 | |||
375 | } |
||
376 | return implode( PHP_EOL, $_aTraces ) . PHP_EOL; |
||
377 | |||
378 | } |
||
379 | /** |
||
380 | * @param array $aTraceArguments |
||
381 | * @return string |
||
382 | * @since 3.8.22 |
||
383 | * @internal |
||
384 | */ |
||
385 | static private function ___getArgumentsOfEachStackTrace( array $aTraceArguments ) { |
||
386 | |||
387 | $_aArguments = array(); |
||
388 | foreach ( $aTraceArguments as $_mArgument ) { |
||
389 | $_sType = gettype( $_mArgument ); |
||
390 | $_sType = str_replace( |
||
391 | array( 'resource (closed)', 'unknown type', 'integer', 'double', ), |
||
392 | array( 'resource', 'unknown', 'scalar', 'scalar', ), |
||
393 | $_sType |
||
394 | ); |
||
395 | $_sMethodName = "___getStackTraceArgument_{$_sType}"; |
||
396 | $_aArguments[] = method_exists( __CLASS__, $_sMethodName ) |
||
397 | ? self::{$_sMethodName}( $_mArgument ) |
||
398 | : $_sType; |
||
399 | } |
||
400 | return join(", ", $_aArguments ); |
||
401 | } |
||
402 | /** |
||
403 | * @since 3.8.22 |
||
404 | * @param mixed $mArgument |
||
405 | * @internal |
||
406 | * @return string |
||
407 | */ |
||
408 | static private function ___getStackTraceArgument_string( $mArgument ) { |
||
409 | $_sString = self::___getLegibleString( $mArgument, 200, true ); |
||
410 | return "'" . $_sString . "'"; |
||
411 | } |
||
412 | static private function ___getStackTraceArgument_scalar( $mArgument ) { |
||
413 | return $mArgument; |
||
414 | } |
||
415 | static private function ___getStackTraceArgument_boolean( $mArgument ) { |
||
416 | return ( $mArgument ) ? "true" : "false"; |
||
417 | } |
||
418 | static private function ___getStackTraceArgument_NULL( $mArgument ) { |
||
419 | return 'NULL'; |
||
420 | } |
||
421 | static private function ___getStackTraceArgument_object( $mArgument ) { |
||
422 | return 'Object(' . get_class( $mArgument ) . ')'; |
||
423 | } |
||
424 | static private function ___getStackTraceArgument_resource( $mArgument ) { |
||
425 | return get_resource_type( $mArgument ); |
||
426 | } |
||
427 | static private function ___getStackTraceArgument_unknown( $mArgument ) { |
||
429 | } |
||
430 | static private function ___getStackTraceArgument_array( $mArgument ) { |
||
431 | $_sOutput = ''; |
||
432 | $_iMax = 10; |
||
433 | $_iTotal = count( $mArgument ); |
||
434 | $_iIndex = 0; |
||
435 | foreach( $mArgument as $_sKey => $_mValue ) { |
||
436 | $_iIndex++; |
||
437 | $_mValue = is_scalar( $_mValue ) |
||
438 | ? self::___getLegibleDetailedScalar( $_mValue, 100 ) |
||
439 | : ucfirst( gettype( $_mValue ) ) . ( |
||
440 | is_object( $_mValue ) |
||
441 | ? ' (' . get_class( $_mValue ) . ')' |
||
442 | : '' |
||
452 | } |
||
453 | |||
454 | } |