AdminPageFramework_Debug_Base   D
last analyzed

Complexity

Total Complexity 59

Size/Duplication

Total Lines 329
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 59
eloc 138
dl 0
loc 329
rs 4.08
c 5
b 0
f 0

21 Methods

Rating   Name   Duplication   Size   Complexity  
A ___getLegibleDetailedScalar() 0 7 4
A ___getCallableName() 0 11 4
A ___getStackTraceArgument_unknown() 0 2 1
A ___getStackTraceArgument_boolean() 0 2 2
A getLegibleDetailedValue() 0 7 3
A ___getArgumentsOfEachStackTrace() 0 15 3
A _getLegible() 0 20 6
A ___getLegibleDetailedNonScalar() 0 13 4
A ___getLegibleDetailedArray() 0 6 2
A ___getStackTraceArgument_object() 0 2 1
A ___getStackTraceArgument_scalar() 0 2 1
A ___getValueLength() 0 9 3
A ___getStackTraceArgument_string() 0 3 1
A _getLegibleDetails() 0 6 2
A ___getStackTraceArgument_array() 0 22 6
A getStackTrace() 0 33 5
A ___getLegibleString() 0 18 6
A ___getStackTraceArgument_NULL() 0 2 1
A ___getStackTraceArgument_resource() 0 2 1
A ___getLegibleDetailedCallable() 0 2 1
A ___getLegibleDetailedObject() 0 5 2

How to fix   Complexity   

Complex Class

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
2
/**
3
 * Admin Page Framework
4
 *
5
 * http://admin-page-framework.michaeluno.jp/
6
 * Copyright (c) 2013-2022, Michael Uno; Licensed MIT
7
 *
8
 */
9
10
/**
11
 * A base class of the debug class.
12
 *
13
 * Mainly provides methods for debug outputs.
14
 *
15
 * @since   3.8.9
16
 * @package AdminPageFramework/Common/Utility
17
 */
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 ) {
185
            if ( is_bool( $sScalar ) ) {
186
                return '(boolean) ' . ( $sScalar ? 'true' : 'false' );
187
            }
188
            return is_string( $sScalar )
189
                ? self::___getLegibleString( $sScalar, $iStringLengthLimit, true )
190
                : '(' . gettype( $sScalar ) . ', length: ' . self::___getValueLength( $sScalar ) .  ') ' . $sScalar;
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 ) {
0 ignored issues
show
introduced by
The condition is_object($iSkip) is always false.
Loading history...
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 ) {
323
                return gettype( $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 )
336
                                ? ' (' . get_class( $_mValue ) . ')'
337
                                : ''
338
                        );
339
                    $_sOutput .= $_sKey . ': ' . $_mValue . ', ';
340
                    if ( $_iIndex > $_iMax && $_iTotal > $_iMax ) {
341
                        $_sOutput  = rtrim( $_sOutput, ','  ) . '...';
342
                        break;
343
                    }
344
                }
345
                $_sOutput = rtrim( $_sOutput, ',' );
346
                return "Array({$_sOutput})";
347
            }
348
349
}