Overview

Namespaces

  • GAubry
    • ErrorHandler
    • Helpers
    • Logger
    • Shell
  • Himedia
    • Padocc
      • DB
      • Minifier
      • Numbering
      • Properties
      • Task
        • Base
        • Extended
  • None
  • Psr
    • Log

Classes

  • Debug
  • Helpers
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: 
  3: namespace GAubry\Helpers;
  4: 
  5: /**
  6:  * Debug class useful for don't forgetting where debug traces are.
  7:  *
  8:  * Automatically decorates print_r() and var_dump() with following information:
  9:  *   – file and line of the caller
 10:  *   – name of function/method containing the call
 11:  *   – name of the parameter passed during call
 12:  *
 13:  * Example:
 14:  * <code>
 15:  *   function f($value) {Debug::printr($value);}
 16:  * </code>
 17:  *
 18:  * Result:
 19:  * <code>
 20:  *   [function f() in file /path/to/file.php, line 31]
 21:  *   $value =
 22:  *   Array
 23:  *   (
 24:  *       [0] => 'xyz'
 25:  *   )
 26:  * </code>
 27:  *
 28:  * See examples/debug.php for a complete example.
 29:  */
 30: class Debug
 31: {
 32: 
 33:     /**
 34:      * Patterns for both HTML and CLI rendering:
 35:      *   %1$s = function name or '∅' if no function
 36:      *   %2$s = filename,
 37:      *   %3$d = line in filename,
 38:      *   %4$s = varname in parameter,
 39:      *   %5$s = value of parameter
 40:      *
 41:      * @var array
 42:      * @see self::displayTrace()
 43:      */
 44:     public static $sDisplayPatterns = array(
 45:         'html' => '<pre><i>[function %1$s in file %2$s, line %3$d]</i><br /><b>%4$s</b> = %5$s</pre>',
 46:         // @codingStandardsIgnoreStart HEREDOC syntax is not supported in array by pdepend…
 47:         'cli'  => "\033[2;33;40m[function \033[1m%1\$s\033[2m in file \033[1m%2\$s\033[2m, line \033[1m%3\$d\033[2m]\n\033[1m%4\$s\033[2m = \033[0m\n%5\$s\n"
 48:         // @codingStandardsIgnoreEnd
 49:     );
 50: 
 51:     /**
 52:      * Constructor.
 53:      *
 54:      * @codeCoverageIgnore
 55:      */
 56:     private function __construct()
 57:     {
 58:     }
 59: 
 60:     /**
 61:      * Returns an array containing function name, filename and line in filename of the caller.
 62:      * If called out of any function, then return '' as function name.
 63:      * To return the caller of your function, either call get_caller(), or get_caller(__FUNCTION__).
 64:      *
 65:      * @see http://stackoverflow.com/a/4767754
 66:      * @author Aram Kocharyan
 67:      * @author Geoffroy Aubry
 68:      *
 69:      * @param string $sFunctionName function whose caller is searched
 70:      * @param array stack trace, or debug_backtrace() by default
 71:      * @return array triplet: (string)function name or '', (string)filename or '', (int)line in filename or 0
 72:      */
 73:     public static function getCaller ($sFunctionName = '', $aStack = array())
 74:     {
 75:         if ($aStack == array()) {
 76:             $aStack = debug_backtrace();
 77:         }
 78: 
 79:         if ($sFunctionName == '') {
 80:             // We need $sFunctionName to be a function name to retrieve its caller. If it is omitted, then
 81:             // we need to first find what function called get_caller(), and substitute that as the
 82:             // default $sFunctionName. Remember that invoking get_caller() recursively will add another
 83:             // instance of it to the function stack, so tell get_caller() to use the current stack.
 84:             list($sFunctionName, , ) = self::getCaller(__FUNCTION__, $aStack);
 85:         }
 86: 
 87:         // If we are given a function name as a string, go through the function stack and find
 88:         // it's caller.
 89:         for ($i = 0; $i < count($aStack); $i++) {
 90:             $aCurrFunction = $aStack[$i];
 91:             // Make sure that a caller exists, a function being called within the main script won't have a caller.
 92:             if ($aCurrFunction['function'] == $sFunctionName && ($i + 1) < count($aStack)) {
 93:                 if (preg_match("/^(.*?)\((\d+)\) : eval\(\)\\'d code$/i", $aStack[$i]['file'], $aMatches) === 1) {
 94:                     return array('eval', $aMatches[1], $aMatches[2]);
 95:                 } else {
 96:                     return array($aStack[$i + 1]['function'], $aStack[$i]['file'], $aStack[$i]['line']);
 97:                 }
 98:             }
 99:         }
100: 
101:         // If out of any function:
102:         if ($aCurrFunction['function'] == $sFunctionName) {
103:             return array('', $aCurrFunction['file'], $aCurrFunction['line']);
104:         } else {
105:             // At this stage, no caller has been found, bummer.
106:             return array('', '', 0);
107:         }
108:     }
109: 
110:     /**
111:      * Return the name of the first parameter of the penultimate function call.
112:      *
113:      * TODO bug if multiple calls in the same line…
114:      *
115:      * @see http://stackoverflow.com/a/6837836
116:      * @author Sebastián Grignoli
117:      * @author Geoffroy Aubry
118:      *
119:      * @param string $sFunction function called
120:      * @param string $sFile file containing a call to $sFunction
121:      * @param int $iLine line in $sFile containing a call to $sFunction
122:      * @return string the name of the first parameter of the penultimate function call.
123:      */
124:     private static function getVarName ($sFunction, $sFile, $iLine)
125:     {
126:         $sContent = file($sFile);
127:         $sLine = $sContent[$iLine - 1];
128:         preg_match("#$sFunction\s*\((.+)\)#", $sLine, $aMatches);
129: 
130:         // Let's count brackets to see how many of them actually belongs to the var name.
131:         // e.g.:    die(catch_param($this->getUser()->hasCredential("delete")));
132:         // We want: $this->getUser()->hasCredential("delete")
133:         $iMax = strlen($aMatches[1]);
134:         $sVarname = '';
135:         $iNb = 0;
136:         for ($i = 0; $i < $iMax; $i++) {
137:             $char = substr($aMatches[1], $i, 1);
138:             if ($char == '(') {
139:                 $iNb++;
140:             } elseif ($char == ')') {
141:                 $iNb--;
142:                 if ($iNb < 0) {
143:                     break;
144:                 }
145:             }
146:             $sVarname .= $char;
147:         }
148: 
149:         // $varname now holds the name of the passed variable ('$' included)
150:         // e.g.: catch_param($hello)
151:         //             => $sVarname = "$hello"
152:         // or the whole expression evaluated
153:         // e.g.: catch_param($this->getUser()->hasCredential("delete"))
154:         //             => $sVarname = "$this->getUser()->hasCredential(\"delete\")"
155:         return $sVarname;
156:     }
157: 
158:     /**
159:      * Use specified pattern to display function name, filename, line in filename,
160:      * varname in parameter and value of this parameter of the caller.
161:      *
162:      * @param string $sPattern key of self::$sDisplayPatterns
163:      * @param string $sValue value of the parameter of the caller
164:      * @see self::$sDisplayPatterns
165:      */
166:     private static function displayTrace ($sPattern, $sValue)
167:     {
168:         list($sDebugFunction, , ) = self::getCaller();
169:         list($sFunction, $sFile, $sLine) = self::getCaller($sDebugFunction);
170:         $sFunction = (empty($sFunction) ? '∅' : "$sFunction()");
171:         $sVarName = self::getVarName($sDebugFunction, $sFile, $sLine);
172:         echo sprintf(self::$sDisplayPatterns[$sPattern], $sFunction, $sFile, $sLine, $sVarName, $sValue);
173:     }
174: 
175:     /**
176:      * Display an HTML trace containing a var_dump() of the specified value.
177:      *
178:      * @param mixed $mValue value to pass to var_dump()
179:      */
180:     public static function htmlVarDump ($mValue)
181:     {
182:         ob_start();
183:         var_dump($mValue);
184:         $sOut = ob_get_contents();
185:         ob_end_clean();
186:         self::displayTrace('html', htmlspecialchars($sOut, ENT_QUOTES));
187:     }
188: 
189:     /**
190:      * Display an HTML trace containing a print_r() of the specified value.
191:      *
192:      * @param mixed $mValue value to pass to print_r()
193:      */
194:     public static function htmlPrintr ($mValue)
195:     {
196:         self::displayTrace('html', htmlspecialchars(print_r($mValue, true), ENT_QUOTES));
197:     }
198: 
199:     /**
200:      * Display a CLI trace containing a var_dump() of the specified value.
201:      *
202:      * @param mixed $mValue value to pass to var_dump()
203:      */
204:     public static function varDump ($mValue)
205:     {
206:         ob_start();
207:         var_dump($mValue);
208:         $sOut = ob_get_contents();
209:         ob_end_clean();
210:         self::displayTrace('cli', $sOut);
211:     }
212: 
213:     /**
214:      * Display a CLI trace containing a print_r() of the specified value.
215:      *
216:      * @param mixed $mValue value to pass to print_r()
217:      */
218:     public static function printr ($mValue)
219:     {
220:         self::displayTrace('cli', print_r($mValue, true));
221:     }
222: }
223: 
Platform for Automatized Deployments with pOwerful Concise Configuration API documentation generated by ApiGen 2.8.0