Total Complexity | 59 |
Total Lines | 329 |
Duplicated Lines | 0 % |
Changes | 5 | ||
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 |
||
18 | class AdminPageFramework_Debug_Base extends AdminPageFramework_Debug_Utility { |
||
19 | |||
20 | /** |
||
21 | * @var integer |
||
22 | * @since 3.8.19 |
||
23 | */ |
||
24 | static public $iLegibleArrayDepthLimit = 50; |
||
25 | |||
26 | /** |
||
27 | * Character length limit to truncate. |
||
28 | */ |
||
29 | static public $iLegibleStringCharacterLimit = 99999; |
||
30 | |||
31 | /** |
||
32 | * Returns a legible value representation with value details. |
||
33 | * @param mixed $mValue |
||
34 | * @param integer $iStringLengthLimit |
||
35 | * @param integer $iArrayDepthLimit |
||
36 | * @return string |
||
37 | * @since 3.8.9 |
||
38 | */ |
||
39 | static protected function _getLegibleDetails( $mValue, $iStringLengthLimit=0, $iArrayDepthLimit=0 ) { |
||
40 | if ( is_array( $mValue ) ) { |
||
41 | return '(array, length: ' . count( $mValue ).') ' |
||
42 | . self::getAsString( print_r( self::___getLegibleDetailedArray( $mValue, $iStringLengthLimit, $iArrayDepthLimit ) , true ) ); |
||
43 | } |
||
44 | return self::getAsString( print_r( self::getLegibleDetailedValue( $mValue, $iStringLengthLimit ), true ) ); |
||
45 | } |
||
46 | |||
47 | /** |
||
48 | * Returns a string representation of the given value with no variable details. |
||
49 | * |
||
50 | * @param $mValue |
||
51 | * @param integer $iStringLengthLimit |
||
52 | * @param integer $iArrayDepthLimit |
||
53 | * @return string |
||
54 | * @since 3.8.9 |
||
55 | * @since 3.8.22 Added the `$sStringLengthLimit` and `$iArrayDepthLimit` parameters. |
||
56 | */ |
||
57 | static protected function _getLegible( $mValue, $iStringLengthLimit=0, $iArrayDepthLimit=0 ) { |
||
58 | |||
59 | $iArrayDepthLimit = $iArrayDepthLimit ? $iArrayDepthLimit : self::$iLegibleArrayDepthLimit; |
||
60 | $mValue = is_object( $mValue ) |
||
61 | ? ( method_exists( $mValue, '__toString' ) |
||
62 | ? ( string ) $mValue // cast string |
||
63 | : ( array ) $mValue // cast array |
||
64 | ) |
||
65 | : $mValue; |
||
66 | $mValue = is_array( $mValue ) |
||
67 | ? self::getArrayMappedRecursive( |
||
68 | array( __CLASS__, 'getObjectName' ), |
||
69 | self::getSlicedByDepth( $mValue, $iArrayDepthLimit ), |
||
70 | array() |
||
71 | ) |
||
72 | : $mValue; |
||
73 | $mValue = is_string( $mValue ) |
||
74 | ? self::___getLegibleString( $mValue, $iStringLengthLimit, false ) |
||
75 | : $mValue; |
||
76 | return self::getArrayRepresentationSanitized( self::getAsString( print_r( $mValue, true ) ) ); |
||
77 | |||
78 | } |
||
79 | |||
80 | /** |
||
81 | * @since 3.8.9 |
||
82 | * @param callable $asoCallable |
||
83 | * @return string |
||
84 | */ |
||
85 | static private function ___getLegibleDetailedCallable( $asoCallable ) { |
||
86 | return '(callable) ' . self::___getCallableName( $asoCallable ); |
||
87 | } |
||
88 | /** |
||
89 | * @since 3.8.9 |
||
90 | * @param callable $asoCallable |
||
91 | * @return string |
||
92 | */ |
||
93 | static public function ___getCallableName( $asoCallable ) { |
||
94 | if ( is_string( $asoCallable ) ) { |
||
95 | return $asoCallable; |
||
96 | } |
||
97 | if ( is_object( $asoCallable ) ) { |
||
98 | return get_class( $asoCallable ); |
||
99 | } |
||
100 | $_sSubject = is_object( $asoCallable[ 0 ] ) |
||
101 | ? get_class( $asoCallable[ 0 ] ) |
||
102 | : ( string ) $asoCallable[ 0 ]; |
||
103 | return $_sSubject . '::' . ( string ) $asoCallable[ 1 ]; |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * @since 3.8.9 |
||
108 | * @param object $oObject |
||
109 | * @return string |
||
110 | */ |
||
111 | static private function ___getLegibleDetailedObject( $oObject ) { |
||
112 | if ( method_exists( $oObject, '__toString' ) ) { |
||
113 | return ( string ) $oObject; |
||
114 | } |
||
115 | return '(object) ' . get_class( $oObject ) . ' ' . count( get_object_vars( $oObject ) ) . ' properties.'; |
||
116 | } |
||
117 | |||
118 | /** |
||
119 | * Returns an array representation with value types in each element. |
||
120 | * The element deeper than 10 dimensions will be dropped. |
||
121 | * @since 3.8.9 |
||
122 | * @since 3.8.22 Added the `$iDepthLimit` parameter |
||
123 | * @since 3.8.22 Changed the scope to private from public. |
||
124 | * @since 3.8.22 Renamed from `_getLegibleArray()`. |
||
125 | * @param array $aArray |
||
126 | * @param integer $iStringLengthLimit |
||
127 | * @param integer $iDepthLimit |
||
128 | * @return array |
||
129 | */ |
||
130 | static private function ___getLegibleDetailedArray( array $aArray, $iStringLengthLimit=0, $iDepthLimit=0 ) { |
||
131 | $_iDepthLimit = $iDepthLimit ? $iDepthLimit : self::$iLegibleArrayDepthLimit; |
||
132 | return self::getArrayMappedRecursive( |
||
133 | array( __CLASS__, 'getLegibleDetailedValue' ), |
||
134 | self::getSlicedByDepth( $aArray, $_iDepthLimit ), |
||
135 | array( $iStringLengthLimit ) |
||
136 | ); |
||
137 | } |
||
138 | |||
139 | /** |
||
140 | * @since 3.8.22 Renamed from `_getLegibleValue()`. |
||
141 | * @since 3.8.9 |
||
142 | * @since 3.8.32 Changed the visibility scope to public from private to be passed as a callback for outside the current class scope. |
||
143 | * And renamed from `___getLegibleDetailedValue()`. |
||
144 | * @param mixed $mItem |
||
145 | * @param integer $iStringLengthLimit |
||
146 | * @return string |
||
147 | */ |
||
148 | static public function getLegibleDetailedValue( $mItem, $iStringLengthLimit ) { |
||
149 | if ( is_callable( $mItem ) ) { |
||
150 | return self::___getLegibleDetailedCallable( $mItem ); |
||
151 | } |
||
152 | return is_scalar( $mItem ) |
||
153 | ? self::___getLegibleDetailedScalar( $mItem, $iStringLengthLimit ) |
||
154 | : self::___getLegibleDetailedNonScalar( $mItem ); |
||
155 | } |
||
156 | /** |
||
157 | * @since 3.8.9 |
||
158 | * @since 3.8.22 Renamed from `_getLegibleNonScalar()`. |
||
159 | * @return string |
||
160 | * @param mixed $mNonScalar |
||
161 | */ |
||
162 | static private function ___getLegibleDetailedNonScalar( $mNonScalar ) { |
||
163 | |||
164 | $_sType = gettype( $mNonScalar ); |
||
165 | if ( is_null( $mNonScalar ) ) { |
||
166 | return '(null)'; |
||
167 | } |
||
168 | if ( is_object( $mNonScalar ) ) { |
||
169 | return self::___getLegibleDetailedObject( $mNonScalar ); |
||
170 | } |
||
171 | if ( is_array( $mNonScalar ) ) { |
||
172 | return '(' . $_sType . ') ' . count( $mNonScalar ) . ' elements'; |
||
173 | } |
||
174 | return '(' . $_sType . ') ' . ( string ) $mNonScalar; |
||
175 | |||
176 | } |
||
177 | /** |
||
178 | * @since 3.8.9 |
||
179 | * @since 3.8.22 Renamed from `_getLegibleScalar()`. |
||
180 | * @param integer|float|boolean|string $sScalar |
||
181 | * @param integer $iStringLengthLimit |
||
182 | * @return string |
||
183 | */ |
||
184 | static private function ___getLegibleDetailedScalar( $sScalar, $iStringLengthLimit ) { |
||
191 | } |
||
192 | /** |
||
193 | * Returns a length of a value.l |
||
194 | * @since 3.5.3 |
||
195 | * @return integer|null For string or integer, the string length. For array, the element lengths. For other types, null. |
||
196 | * @param mixed $mValue |
||
197 | */ |
||
198 | static private function ___getValueLength( $mValue ) { |
||
199 | $_sVariableType = gettype( $mValue ); |
||
200 | if ( in_array( $_sVariableType, array( 'string', 'integer' ) ) ) { |
||
201 | return strlen( $mValue ); |
||
202 | } |
||
203 | if ( 'array' === $_sVariableType ) { |
||
204 | return count( $mValue ); |
||
205 | } |
||
206 | return null; |
||
207 | } |
||
208 | /** |
||
209 | * @param string $sString |
||
210 | * @param integer $iLengthLimit |
||
211 | * @param boolean $bShowDetails |
||
212 | * @return string |
||
213 | */ |
||
214 | static private function ___getLegibleString( $sString, $iLengthLimit, $bShowDetails=true ) { |
||
215 | |||
216 | static $_iMBSupport; |
||
217 | $_iMBSupport = isset( $_iMBSupport ) ? $_iMBSupport : ( integer ) function_exists( 'mb_strlen' ); |
||
218 | $_aStrLenMethod = array( 'strlen', 'mb_strlen' ); |
||
219 | $_aSubstrMethod = array( 'substr', 'mb_substr' ); |
||
220 | $iCharLimit = $iLengthLimit ? $iLengthLimit : self::$iLegibleStringCharacterLimit; |
||
221 | $_iCharLength = call_user_func_array( $_aStrLenMethod[ $_iMBSupport ], array( $sString ) ); |
||
222 | |||
223 | if ( $bShowDetails ) { |
||
224 | return $_iCharLength <= $iCharLimit |
||
225 | ? '(string, length: ' . $_iCharLength . ') ' . $sString |
||
226 | : '(string, length: ' . $_iCharLength . ') ' . call_user_func_array( $_aSubstrMethod[ $_iMBSupport ], array( $sString, 0, $iCharLimit ) ) |
||
227 | . '...'; |
||
228 | } |
||
229 | return $_iCharLength <= $iCharLimit |
||
230 | ? $sString |
||
231 | : call_user_func_array( $_aSubstrMethod[ $_iMBSupport ], array( $sString, 0, $iCharLimit ) ); |
||
232 | |||
233 | } |
||
234 | |||
235 | /** |
||
236 | * @param integer $iSkip The number of skipping records. This is used when the caller does not want to include the self function/method. |
||
237 | * @param null|mixed $_deprecated |
||
238 | * @return string |
||
239 | * @since 3.8.22 |
||
240 | * @since 3.8.23 Deprecated the `$oException` parameter. |
||
241 | */ |
||
242 | static public function getStackTrace( $iSkip=0, $_deprecated=null ) { |
||
243 | |||
244 | $_iSkip = 1; // need to skip this method trace itself |
||
245 | $_oException = new Exception(); |
||
246 | |||
247 | // Backward compatibility. |
||
248 | if ( is_object( $iSkip ) && $iSkip instanceof Exception ) { |
||
|
|||
249 | $_oException = $iSkip; |
||
250 | $iSkip = ( integer ) $_deprecated; |
||
251 | } |
||
252 | |||
253 | $_iSkip = $_iSkip + $iSkip; |
||
254 | $_aTraces = array(); |
||
255 | $_aFrames = $_oException->getTrace(); |
||
256 | $_aFrames = array_slice( $_aFrames, $_iSkip ); |
||
257 | foreach ( array_reverse( $_aFrames ) as $_iIndex => $_aFrame ) { |
||
258 | |||
259 | $_aFrame = $_aFrame + array( |
||
260 | 'file' => null, 'line' => null, 'function' => null, |
||
261 | 'class' => null, 'args' => array(), |
||
262 | ); |
||
263 | $_sArguments = self::___getArgumentsOfEachStackTrace( $_aFrame[ 'args' ] ); |
||
264 | $_aTraces[] = sprintf( |
||
265 | "#%s %s(%s): %s(%s)", |
||
266 | $_iIndex + 1, |
||
267 | $_aFrame[ 'file' ], |
||
268 | $_aFrame[ 'line' ], |
||
269 | isset( $_aFrame[ 'class' ] ) ? $_aFrame[ 'class' ] . '->' . $_aFrame[ 'function' ] : $_aFrame[ 'function' ], |
||
270 | $_sArguments |
||
271 | ); |
||
272 | |||
273 | } |
||
274 | return implode( PHP_EOL, $_aTraces ) . PHP_EOL; |
||
275 | |||
276 | } |
||
277 | /** |
||
278 | * @param array $aTraceArguments |
||
279 | * @return string |
||
280 | * @since 3.8.22 |
||
281 | */ |
||
282 | static private function ___getArgumentsOfEachStackTrace( array $aTraceArguments ) { |
||
283 | $_aArguments = array(); |
||
284 | foreach ( $aTraceArguments as $_mArgument ) { |
||
285 | $_sType = gettype( $_mArgument ); |
||
286 | $_sType = str_replace( |
||
287 | array( 'resource (closed)', 'unknown type', 'integer', 'double', ), |
||
288 | array( 'resource', 'unknown', 'scalar', 'scalar', ), |
||
289 | $_sType |
||
290 | ); |
||
291 | $_sMethodName = "___getStackTraceArgument_{$_sType}"; |
||
292 | $_aArguments[] = method_exists( __CLASS__, $_sMethodName ) |
||
293 | ? self::{$_sMethodName}( $_mArgument ) |
||
294 | : $_sType; |
||
295 | } |
||
296 | return join(", ", $_aArguments ); |
||
297 | } |
||
298 | /** |
||
299 | * @since 3.8.22 |
||
300 | * @param mixed $mArgument |
||
301 | * @return string |
||
302 | */ |
||
303 | static private function ___getStackTraceArgument_string( $mArgument ) { |
||
304 | $_sString = self::___getLegibleString( $mArgument, 200, true ); |
||
305 | return "'" . $_sString . "'"; |
||
306 | } |
||
307 | static private function ___getStackTraceArgument_scalar( $mArgument ) { |
||
308 | return $mArgument; |
||
309 | } |
||
310 | static private function ___getStackTraceArgument_boolean( $mArgument ) { |
||
311 | return ( $mArgument ) ? "true" : "false"; |
||
312 | } |
||
313 | static private function ___getStackTraceArgument_NULL( $mArgument ) { |
||
314 | return 'NULL'; |
||
315 | } |
||
316 | static private function ___getStackTraceArgument_object( $mArgument ) { |
||
317 | return 'Object(' . get_class( $mArgument ) . ')'; |
||
318 | } |
||
319 | static private function ___getStackTraceArgument_resource( $mArgument ) { |
||
320 | return get_resource_type( $mArgument ); |
||
321 | } |
||
322 | static private function ___getStackTraceArgument_unknown( $mArgument ) { |
||
324 | } |
||
325 | static private function ___getStackTraceArgument_array( $mArgument ) { |
||
326 | $_sOutput = ''; |
||
327 | $_iMax = 10; |
||
328 | $_iTotal = count( $mArgument ); |
||
329 | $_iIndex = 0; |
||
330 | foreach( $mArgument as $_sKey => $_mValue ) { |
||
331 | $_iIndex++; |
||
332 | $_mValue = is_scalar( $_mValue ) |
||
333 | ? self::___getLegibleDetailedScalar( $_mValue, 100 ) |
||
334 | : ucfirst( gettype( $_mValue ) ) . ( |
||
335 | is_object( $_mValue ) |
||
347 | } |
||
348 | |||
349 | } |