Completed
Branch dev (11654d)
by
unknown
06:28
created

AdminPageFramework_Debug::_getLegibleValue()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 8
nc 5
nop 1
dl 0
loc 15
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * Admin Page Framework
4
 * 
5
 * http://en.michaeluno.jp/admin-page-framework/
6
 * Copyright (c) 2013-2016 Michael Uno; Licensed MIT
7
 * 
8
 */
9
10
/**
11
 * Provides debugging methods.
12
 * 
13
 * Use the methods of this class to check variable contents. 
14
 *
15
 * @image           http://admin-page-framework.michaeluno.jp/image/common/utility/debug.png
16
 * @since           2.0.0
17
 * @since           3.1.3       Extends AdminPageFramework_WPUtility
18
 * @since           3.7.1       Extends AdminPageFramework_FrameworkUtility
19
 * @extends         AdminPageFramework_FrameworkUtility
20
 * @package         AdminPageFramework
21
 * @subpackage      Common/Utility
22
 */
23
class AdminPageFramework_Debug extends AdminPageFramework_FrameworkUtility {
24
            
25
    /**
26
     * Prints out the given variable contents
27
     * 
28
     * If a file pass is given to the second parameter, it saves the output in the file.
29
     * 
30
     * @since       3.2.0
31
     * @remark      An alias of the dumpArray() method.
32
     * @param       array|string    $asArray        The variable to check its contents.
33
     * @param       string          $sFilePath      The file path for a log file.
34
     * @return      void
35
     */
36
    static public function dump( $asArray, $sFilePath=null ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
37
        echo self::get( $asArray, $sFilePath );
38
    }    
39
        /**
40
         * Prints out the given variable contents.
41
         * 
42
         * If a file pass is given, it saves the output in the file.
43
         * 
44
         * @since unknown
45
         * @deprecated      3.2.0
46
         */
47
        static public function dumpArray( $asArray, $sFilePath=null ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
48
            self::dump( $asArray, $sFilePath );
49
        }    
50
        
51
    /**
52
     * Retrieves the output of the given variable contents.
53
     * 
54
     * If a file pass is given to the second parameter, it saves the output in the file.
55
     * 
56
     * @remark      An alias of getArray() method.
57
     * @since       3.2.0
58
     * @param       array|string    $asArray        The variable to check its contents.
59
     * @param       string          $sFilePath      The file path for a log file.
60
     * @param       boolean         $bEscape        Whether to escape characters.
61
     */
62
    static public function get( $asArray, $sFilePath=null, $bEscape=true ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
63
64
        if ( $sFilePath ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $sFilePath of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
65
            self::log( $asArray, $sFilePath );     
66
        }
67
        
68
        return $bEscape
69
            ? "<pre class='dump-array'>" 
70
                    . htmlspecialchars( self::getAsString( $asArray ) ) // `esc_html()` breaks with complex HTML code.
71
                . "</pre>" 
72
            : self::getAsString( $asArray ); // non-escape is used for exporting data into file.    
73
        
74
    }
75
        /**
76
         * Retrieves the output of the given array contents.
77
         * 
78
         * If a file pass is given, it saves the output in the file.
79
         * 
80
         * @since       2.1.6 The $bEncloseInTag parameter is added.
81
         * @since       3.0.0 Changed the $bEncloseInTag parameter to bEscape.
82
         * @deprecated  3.2.0
83
         */
84
        static public function getArray( $asArray, $sFilePath=null, $bEscape=true ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
85
            self::showDeprecationNotice( __CLASS__ .'::' . __FUNCTION__,  __CLASS__ .'::get()' );
86
            return self::get( $asArray, $sFilePath, $bEscape );
87
        }      
88
            
89
    /**
90
     * Logs the given variable output to a file.
91
     * 
92
     * <h4>Example</h4>
93
     * <code>
94
     * $_aValues = array( 'foo', 'bar' );
95
     * AdminPageFramework_Debug::log( $aValues );
96
     * </code>
97
     * 
98
     * @remark      The alias of the `logArray()` method.
99
     * @since       3.1.0
100
     * @since       3.1.3       Made it leave milliseconds and elapsed time from the last call of the method.
101
     * @since       3.3.0       Made it indicate the data type.
102
     * @since       3.3.1       Made it indicate the data length.
103
     * @param       mixed       $mValue         The value to log.  
104
     * @param       string      $sFilePath      The log file path.
105
     * @return      void
106
     **/
107
    static public function log( $mValue, $sFilePath=null ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
108
                
109
        static $_fPreviousTimeStamp = 0;
110
        
111
        $_oCallerInfo       = debug_backtrace();
112
        $_sCallerFunction   = self::getElement(
113
            $_oCallerInfo,  // subject array
114
            array( 1, 'function' ), // key
115
            ''      // default
116
        );                        
117
        $_sCallerClass      = self::getElement(
118
            $_oCallerInfo,  // subject array
119
            array( 1, 'class' ), // key
120
            ''      // default
121
        );           
122
        $_fCurrentTimeStamp = microtime( true );
123
        
124
        file_put_contents( 
125
            self::_getLogFilePath( $sFilePath, $_sCallerClass ), 
126
            self::_getLogHeadingLine( 
127
                $_fCurrentTimeStamp,
128
                round( $_fCurrentTimeStamp - $_fPreviousTimeStamp, 3 ),     // elapsed time
129
                $_sCallerClass,
130
                $_sCallerFunction
131
            ) . PHP_EOL
132
            . self::_getLogContents( $mValue ),
133
            FILE_APPEND 
134
        );     
135
        
136
        $_fPreviousTimeStamp = $_fCurrentTimeStamp;
137
        
138
    }   
139
        /**
140
         * Determines the log file path.
141
         * @since       3.5.3 
142
         * @internal    
143
         * @return      string      The path of the file to log the contents.
144
         */
145
        static private function _getLogFilePath( $bsFilePath, $sCallerClass ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
146
        
147
            $_bFileExists = self::_createFile( $bsFilePath );
148
            if ( $_bFileExists ) {
149
                return $bsFilePath;
150
            }
151
            // Return a generated default log path.
152
            if ( true === $bsFilePath ) {
153
                return WP_CONTENT_DIR . DIRECTORY_SEPARATOR . basename( get_class() ) . '_' . date( "Ymd" ) . '.log';
154
            }
155
            return WP_CONTENT_DIR . DIRECTORY_SEPARATOR . basename( get_class() ) . '_' . basename( $sCallerClass ) . '_' . date( "Ymd" ) . '.log';
156
            
157
        }
158
            /**
159
             * Creates a file.
160
             * @return      boolean
161
             * @internal
162
             */
163
            static private function _createFile( $sFilePath ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
164
                if ( ! $sFilePath || true === $sFilePath ) {
165
                    return false;
166
                }
167
                if ( file_exists( $sFilePath ) ) {
168
                    return true;
169
                }
170
                // Otherwise, create a file.
171
                $_bhResrouce = fopen( $sFilePath, 'w' );
172
                return ( boolean ) $_bhResrouce;                
173
            }
174
            
175
        /**
176
         * Returns the log contents.
177
         * @internal
178
         * @since       3.5.3
179
         * @param       mixed       $mValue     The value to log.  
180
         */
181
        static private function _getLogContents( $mValue ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
182
183
            $_sType     = gettype( $mValue );
184
            $_iLengths  = self::_getValueLength( $mValue, $_sType );
185
            return '(' 
186
                . $_sType
187
                . ( null !== $_iLengths ? ', length: ' . $_iLengths : '' )
188
            . ') '
189
            . self::getAsString( $mValue ) 
190
            . PHP_EOL . PHP_EOL;
191
        
192
        }      
193
            /**
194
             * Returns a length of a value.
195
             * @since       3.5.3
196
             * @internal
197
             * @return      integer|null        For string or integer, the string length. For array, the element lengths. For other types, null.
198
             */
199
            static private function _getValueLength( $mValue, $sVariableType ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
200
                
201
                if ( in_array( $sVariableType, array( 'string', 'integer' ) ) ) {
202
                    return strlen( $mValue );
203
                }
204
                if ( 'array' === $sVariableType ) {
205
                    return count( $mValue );
206
                }
207
                return null;
208
                
209
            }
210
        /**
211
         * Returns the heading part of a log item.
212
         * @since       3.5.3
213
         * @internal
214
         * @return      string      the heading part of a log item.
215
         */
216
        static private function _getLogHeadingLine( $fCurrentTimeStamp, $nElapsed, $sCallerClass, $sCallerFunction ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
217
            
218
            static $_iPageLoadID; // identifies the page load.
219
            static $_nGMTOffset;
220
            
221
            $_nGMTOffset        = isset( $_nGMTOffset ) 
222
                ? $_nGMTOffset 
223
                : get_option( 'gmt_offset' );
224
            $_iPageLoadID       = $_iPageLoadID 
225
                ? $_iPageLoadID 
226
                : uniqid();
227
            $_nNow              = $fCurrentTimeStamp + ( $_nGMTOffset * 60 * 60 );
228
            $_nMicroseconds     = str_pad( round( ( $_nNow - floor( $_nNow ) ) * 10000 ), 4, '0' );
229
            
230
            $_aOutput           = array(
231
                date( "Y/m/d H:i:s", $_nNow ) . '.' . $_nMicroseconds,
232
                self::_getFormattedElapsedTime( $nElapsed ),
233
                $_iPageLoadID,
234
                AdminPageFramework_Registry::getVersion(),
235
                $sCallerClass . '::' . $sCallerFunction,
236
                current_filter(),
237
                self::getCurrentURL(),
238
            );
239
            return implode( ' ', $_aOutput );         
240
            
241
        }
242
            /**
243
             * Returns formatted elapsed time.
244
             * @since       3.5.3
245
             * @internal
246
             * @return      string      Formatted elapsed time.
247
             */
248
            static private function _getFormattedElapsedTime( $nElapsed ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
249
                
250
                $_aElapsedParts     = explode( ".", ( string ) $nElapsed );
251
                $_sElapsedFloat     = str_pad(
252
                    self::getElement(
253
                        $_aElapsedParts,  // subject array
254
                        1, // key
255
                        0      // default
256
                    ),      
257
                    3, 
258
                    '0'
259
                );
260
                $_sElapsed          = self::getElement(
261
                    $_aElapsedParts,  // subject array
262
                    0,  // key
263
                    0   // default
264
                );                                   
265
                $_sElapsed          = strlen( $_sElapsed ) > 1 
266
                    ? '+' . substr( $_sElapsed, -1, 2 ) 
267
                    : ' ' . $_sElapsed;
268
                return $_sElapsed . '.' . $_sElapsedFloat;
269
            
270
            }
271
        /**
272
         * Logs the given array output into the given file.
273
         * 
274
         * @since       2.1.1
275
         * @since       3.0.3   Changed the default log location and file name.
276
         * @deprecated  3.1.0   Use the `log()` method instead.
277
         */
278
        static public function logArray( $asArray, $sFilePath=null ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
279
            self::showDeprecationNotice( __CLASS__ .'::' . __FUNCTION__,  __CLASS__ .'::log()' );
280
            self::log( $asArray, $sFilePath );     
281
        }      
282
        
283
    /**
284
     * Returns a string representation of the given value.
285
     * @since       3.5.0
286
     * @param       mixed       $mValue     The value to get as a string
287
     * @internal
288
     */
289
    static public function getAsString( $mValue ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
290
        
291
        $mValue = self::_getLegibleObject( $mValue );
292
        $mValue = self::_getLegibleCallable( $mValue );
293
        $mValue = self::_getLegibleArray( $mValue );            
294
        return print_r( $mValue, true );
295
        
296
    }
297
        /**
298
         * @since       3.8.9
299
         * @return      mixed
300
         */
301
        static private function _getLegibleCallable( $asoCallable ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
302
            
303
            if ( ! is_callable( $asoCallable ) ) {
304
                return $asoCallable;
305
            }
306
            if ( is_string( $asoCallable ) ) {
307
                return '(callable) ' . $asoCallable;
308
            }
309
            if ( is_object( $asoCallable ) ) {
310
                return '(callable) ' . get_class( $asoCallable );
311
            }
312
            $_sSubject = is_object( $asoCallable[ 0 ] )
313
                ? get_class( $asoCallable[ 0 ] )
314
                : ( string ) $asoCallable[ 0 ];
315
316
            return '(callable) ' . $_sSubject . '::' . ( string ) $asoCallable[ 1 ];
317
            
318
        }
319
        
320
        /**
321
         * @since       3.8.9
322
         * @return      mixed
323
         */
324
        static public function _getLegibleObject( $oObject ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
325
            
326
            if ( ! is_object( $oObject ) ) {
327
                return $oObject;
328
            }
329
            
330
            if ( method_exists( $oObject, '__toString' ) ) {
331
                return ( string ) $oObject;
332
            }
333
            
334
            return '(object) ' . get_class( $oObject ) . ' ' 
335
                . count( get_object_vars( $oObject ) ) . ' properties.';
336
            
337
        }
338
        
339
        /**
340
         * @since       3.8.9
341
         * @return      mixed
342
         */
343
        static public function _getLegibleArray( $aArray ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
344
            
345
            if ( ! is_array( $aArray ) ) {
346
                return $aArray;
347
            }
348
            return self::_getArrayMappedRecursive( 
349
                self::getSliceByDepth( $aArray, 10 ), 
350
                array( __CLASS__, '_getLegibleValue' ) 
351
            );
352
            
353
        }
354
 
355
    /**
356
     * Slices the given array by depth.
357
     * 
358
     * @since       3.4.4
359
     * @since       3.8.9       Changed it not to convert an object into an array.
360
     * @return      array
361
     * @internal
362
     */
363
    static public function getSliceByDepth( array $aSubject, $iDepth=0 ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
364
365
        foreach ( $aSubject as $_sKey => $_vValue ) {
366
            if ( is_array( $_vValue ) ) {
367
                $_iDepth = $iDepth;
368
                if ( $iDepth > 0 ) {
369
                    $aSubject[ $_sKey ] = self::getSliceByDepth( $_vValue, --$iDepth );
370
                    $iDepth = $_iDepth;
371
                    continue;
372
                } 
373
                unset( $aSubject[ $_sKey ] );
374
            }
375
        }
376
        return $aSubject;
377
        
378
    }        
379
380
        /**
381
         * @return      string
382
         * @since       3.8.9
383
         */
384
        static private function _getLegibleValue( $mItem ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
385
            
386
            if ( is_object( $mItem ) ) {
387
                return '(object) ' . get_class( $mItem );
388
            }
389
            if ( is_null( $mItem ) ) {
390
                return '(null)';
391
            }
392
            if ( is_bool( $mItem ) ) {
393
                return '(boolean) ' . ( $mItem ? 'true' : 'false' );
394
            }
395
            // At this point, the value is a scalar.
396
            return self::_getLegibleString( $mItem );
397
398
        }
399
            /**
400
             * @return      string
401
             * @since       3.8.9
402
             */
403
            static private function _getLegibleString( $sScalar, $iCharLimit=300 ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
404
                
405
                static $_iMBSupport;
406
                $_iMBSupport = isset( $_iMBSupport ) ? $_iMBSupport : function_exists( 'mb_strlen' );      
407
                $_aStrLenMethod = array( 'strlen', 'mb_strlen' );
408
                $_aSubstrMethod = array( 'substr', 'mb_substr' );
409
                
410
                $_iCharLength = call_user_func_array( $_aStrLenMethod[ $_iMBSupport ], array( $sScalar ) );
411
                if ( $_iCharLength <= $iCharLimit ) {
412
                    return '(' . gettype( $sScalar ) . ') ' . $sScalar;
413
                }
414
                return '(' . gettype( $sScalar ) . ') '
415
                    . call_user_func_array( $_aSubstrMethod[ $_iMBSupport ], array( $sScalar, 0, $iCharLimit ) ) 
416
                    . '...';
417
                    
418
            }
419
        /**
420
         * Performs `array_map()` recursively.
421
         * @return      array.
0 ignored issues
show
Documentation introduced by
The doc-type array. could not be parsed: Unknown type name "array." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
422
         * @since       3.8.9
423
         */
424
        static private function _getArrayMappedRecursive( array $aArray, $oCallable ) {
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
425
            
426
            self::$oCurrentCallable = $oCallable;
427
            $_aArray = array_map( array( __CLASS__, '_getArrayMappedNested' ), $aArray );
428
            self::$oCurrentCallable = null;
429
            return $_aArray;
430
            
431
        }
432
            static public $oCurrentCallable;
433
            /**
434
             * @internal
435
             * @return      mixed       A modified value.
436
             * @since       3.8.9
437
             */
438
            static private function _getArrayMappedNested( $mItem ) {            
1 ignored issue
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
439
                return is_array( $mItem ) 
440
                    ? array_map( array( __CLASS__, '_getArrayMappedNested' ), $mItem ) 
441
                    : call_user_func( self::$oCurrentCallable, $mItem );            
442
            }    
443
    
444
}
445