├── CHANGELOG.md ├── LICENSE ├── README.md ├── composer.json ├── src ├── ArrayIterator.php ├── Checker.php ├── Exception │ ├── Exception.php │ ├── FileNotFound.php │ ├── FileOpen.php │ ├── InvalidArgument.php │ └── NotExistsPath.php ├── FunctionArgument.php ├── FunctionConditions.php ├── Manager.php ├── Output.php ├── OutputColored.php ├── RecursiveDirectoryFilterIterator.php ├── Result.php ├── Settings.php └── Writer │ ├── Console.php │ ├── File.php │ ├── Multiple.php │ └── Writer.php ├── var-dump-check └── var-dump-check.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). 6 | 7 | ## [Unreleased] 8 | 9 | ### Internal 10 | 11 | - PHPUnit - Make the unit tests cross version compatible [#12](https://github.com/php-parallel-lint/PHP-Var-Dump-Check/pull/12) from [@jrfnl](https://github.com/jrfnl). 12 | - Travis: run the tests on PHP 8/nightly [#13](https://github.com/php-parallel-lint/PHP-Var-Dump-Check/pull/13) from [@jrfnl](https://github.com/jrfnl). 13 | 14 | ## [v0.5] - 2020-08-17 15 | 16 | ### Added 17 | 18 | - Added `--custom-function` parameter to check custom debug functions [#10](https://github.com/php-parallel-lint/PHP-Var-Dump-Check/pull/10) from [@umutphp](https://github.com/umutphp). 19 | - Added .gitattributes from [@reedy](https://github.com/reedy). 20 | 21 | ### Fixed 22 | 23 | - PHP 7.4: fix compatibility issue [#7](https://github.com/php-parallel-lint/PHP-Var-Dump-Check/pull/7) from [@jrfnl](https://github.com/jrfnl). 24 | 25 | ### Internal 26 | 27 | - Replaced array syntax with short array syntax from [@peter279k](https://github.com/peter279k). 28 | - Added EOF (end of file) for some PHP files from [@peter279k](https://github.com/peter279k). 29 | - Removed $loader variable on bootstrap.php file because it's unused from [@peter279k](https://github.com/peter279k). 30 | - To be compatible with future PHPUnit version, using the ^4.8.36 version at least from [@peter279k](https://github.com/peter279k). 31 | - Changed namespace to PHPunit\Framework\TestCase class namesapce from [@peter279k](https://github.com/peter279k). 32 | - Composer: allow installation of more recent Parallel Lint [#9](https://github.com/php-parallel-lint/PHP-Var-Dump-Check/pull/9) from [@jrfnl](https://github.com/jrfnl). 33 | - Travis: removed sudo [#8](https://github.com/php-parallel-lint/PHP-Var-Dump-Check/pull/8) from [@jrfnl](https://github.com/jrfnl). 34 | - Travis: removed Composer option `--prefer-source` [#8](https://github.com/php-parallel-lint/PHP-Var-Dump-Check/pull/8) from [@jrfnl](https://github.com/jrfnl). 35 | 36 | ## [v0.4] - 2020-04-25 37 | 38 | ### Added 39 | 40 | - Added check for Symfony dump function `dd` from [@antograssiot](https://github.com/antograssiot). 41 | - Added check for Laravel dump function `dump` from [@Douglasdc3](https://github.com/Douglasdc3). 42 | - Added changelog. 43 | - Added support for PHP 7.4. 44 | 45 | ### Internal 46 | 47 | - Fixed running tests in PHP 5.4 and PHP 5.5 in CI. 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Jakub Onderka 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those 25 | of the authors and should not be interpreted as representing official policies, 26 | either expressed or implied, of the FreeBSD Project. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PHP VarDump Check 2 | ================= 3 | 4 | PHP console application for find forgotten variable dump. Support PHP build in method 5 | `print_r`, `var_dump` and `var_export` method and also method from Tracy debugger, Ladybug, 6 | Symfony, Laravel, Doctrine and Zend Framework. 7 | 8 | Install 9 | ------- 10 | 11 | Just create a `composer.json` file and run the `php composer.phar install` command to install it: 12 | 13 | ```json 14 | { 15 | "require-dev": { 16 | "php-parallel-lint/php-var-dump-check": "~0.4" 17 | } 18 | } 19 | ``` 20 | 21 | For colored output install suggested package `php-parallel-lint/php-console-highlighter`. 22 | 23 | Usage and example output 24 | -------------- 25 | 26 | ``` 27 | $ ./vendor/bin/var-dump-check --no-colors --tracy . 28 | ...................X... 29 | 30 | Checked 23 files in 0.1 second, dump found in 1 file 31 | 32 | ------------------------------------------------------------ 33 | Forgotten dump 'var_dump' found in ./test.php:36 34 | 34| $functionsToCheck = $this->prepareFunctionCheck($this->settings->functionsToCheck); 35 | 35| 36 | > 36| var_dump($functionsToCheck); 37 | 37| 38 | 38| foreach ($tokens as $key => $token) { 39 | ``` 40 | 41 | Options for run 42 | --------------- 43 | 44 | - none - check dump: `var_dump`, `var_export`, `print_r` 45 | - `--ladybug` - check dump: `ladybug_dump`, `ladybug_dump_die`, `ld`, `ldd` 46 | - `--tracy` - check dump: `dump`, `bdump`, `Debugger::dump`, `Debugger::barDump` 47 | - `--zend` - check dump: `Zend_Debug::dump`, `\Zend\Debug\Debug::dump` 48 | - `--doctrine` - check dump: `Doctrine::dump`, `\Doctrine\Common\Util\Debug::dump` 49 | - `--symfony` - check dump: `dump`, `VarDumper::dump`, `VarDumper::setHandler`, `VarDumper::dd` 50 | - `--laravel` - check dump: `dd`, `dump` 51 | - `--no-colors` - disable colors from output 52 | - `--exclude folder/` - exclude *folder/* from check 53 | - `--extensions php,phpt,php7` - map file extensions for check 54 | 55 | Recommended setting for usage with Symfony framework 56 | -------------- 57 | 58 | For run from command line: 59 | 60 | ``` 61 | $ ./vendor/bin/var-dump-check --symfony --exclude app --exclude vendor . 62 | ``` 63 | 64 | or setting for ANT: 65 | 66 | ```xml 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | ``` 79 | 80 | ------ 81 | 82 | [![Build Status](https://github.com/php-parallel-lint/PHP-Var-Dump-Check/actions/workflows/test.yml/badge.svg)](https://github.com/php-parallel-lint/PHP-Var-Dump-Check/actions/workflows/test.yml) 83 | [![Downloads this Month](https://img.shields.io/packagist/dm/php-parallel-lint/php-var-dump-check.svg)](https://packagist.org/packages/php-parallel-lint/php-var-dump-check) 84 | [![Latest stable](https://img.shields.io/packagist/v/php-parallel-lint/php-var-dump-check.svg)](https://packagist.org/packages/php-parallel-lint/php-var-dump-check) 85 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "php-parallel-lint/php-var-dump-check", 3 | "license": "BSD-2-Clause", 4 | "description": "Find forgotten variables dump in PHP source code.", 5 | "authors": [ 6 | { 7 | "name": "Jakub Onderka", 8 | "email": "jakub.onderka@gmail.com" 9 | } 10 | ], 11 | "autoload": { 12 | "psr-4": {"JakubOnderka\\PhpVarDumpCheck\\": "src/"} 13 | }, 14 | "require": { 15 | "php": ">=5.4.0" 16 | }, 17 | "suggest": { 18 | "php-parallel-lint/php-console-highlighter": "For colored console output" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": "^4.8.36 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0", 22 | "php-parallel-lint/php-parallel-lint": "^1.0" 23 | }, 24 | "bin": ["var-dump-check"], 25 | "replace": { 26 | "jakub-onderka/php-var-dump-check": "*" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ArrayIterator.php: -------------------------------------------------------------------------------- 1 | next(); 9 | return $this->current(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/Checker.php: -------------------------------------------------------------------------------- 1 | settings = $settings; 12 | } 13 | 14 | /** 15 | * @param string $content 16 | * @return Result[] 17 | */ 18 | public function check($content) 19 | { 20 | $tokens = $this->tokenize($content); 21 | $results = $this->checkForDumps($tokens); 22 | 23 | return $results; 24 | } 25 | 26 | /** 27 | * @param array $tokens 28 | * @return Result[] 29 | */ 30 | protected function checkForDumps(array $tokens) 31 | { 32 | $results = []; 33 | 34 | $functionsToCheck = $this->prepareFunctionCheck($this->settings->functionsToCheck); 35 | 36 | foreach ($tokens as $key => $token) { 37 | if ( 38 | is_array($token) && 39 | (($token[0] === T_STRING && isset($functionsToCheck[$token[1]])) || isset($functionsToCheck[$token[0]])) 40 | ) { 41 | if ( 42 | !$this->checkPrevTokens($tokens, $key) || 43 | !$this->checkNextTokens($tokens, $functionsToCheck, $key) 44 | ) { 45 | continue; 46 | } 47 | 48 | $conditions = $this->settings->getFunctionCondition($token[1]); 49 | list($prediction, $sure) = $this->checkFunctionCall($tokens, $key, $conditions); 50 | 51 | if ($prediction === true || $sure === false) { 52 | $results[] = new Result($token[1], $token[2], $sure); 53 | } 54 | } 55 | } 56 | 57 | return $results; 58 | } 59 | 60 | /** 61 | * @param array $tokens 62 | * @param int $key 63 | * @return bool 64 | */ 65 | protected function checkPrevTokens(array $tokens, $key) 66 | { 67 | $prevToken = $tokens[$key - 1]; 68 | 69 | if (is_array($prevToken)) { 70 | return $prevToken[0] === T_OPEN_TAG || $prevToken[0] === T_OPEN_TAG_WITH_ECHO || $prevToken[0] === T_NS_SEPARATOR; 71 | } else { 72 | return $prevToken === '{' || $prevToken === ';' || $prevToken === '}'; 73 | } 74 | } 75 | 76 | /** 77 | * @param array $tokens 78 | * @param array $functionsToCheck 79 | * @param int $key 80 | * @return bool 81 | */ 82 | protected function checkNextTokens(array $tokens, array $functionsToCheck, $key) 83 | { 84 | $next = &$functionsToCheck; 85 | 86 | do { 87 | $currentToken = $tokens[$key++]; 88 | 89 | if (!is_array($currentToken)) { 90 | return false; 91 | } 92 | 93 | if ($currentToken[0] === T_STRING && isset($next[$currentToken[1]])) { 94 | $next = &$next[$currentToken[1]]; 95 | } else if (isset($next[$currentToken[0]])) { 96 | $next = &$next[$currentToken[0]]; 97 | } else { 98 | return false; 99 | } 100 | 101 | if (empty($next)) { 102 | return true; 103 | } 104 | } while (true); 105 | } 106 | 107 | /** 108 | * @param array $tokens 109 | * @param int $from 110 | * @param FunctionConditions|null $conditions 111 | * @return array 112 | */ 113 | protected function checkFunctionCall(array $tokens, $from, FunctionConditions $conditions = null) 114 | { 115 | /** @var FunctionArgument[] $arguments */ 116 | list($ok, $arguments) = $this->checkIsFunctionCall($tokens, $from); 117 | 118 | if (!$ok) { 119 | return [false, true]; 120 | } 121 | 122 | if ($conditions) { 123 | if (isset($arguments[$conditions->getArgumentNumber() - 1])) { 124 | list($isTrue, $sure) = $arguments[$conditions->getArgumentNumber() - 1]->isTrue(); 125 | return [$isTrue === $conditions->getMustBe(), $sure]; 126 | } else { 127 | return $conditions->getMustBe() === $conditions->getDefault() ? [true, true] : [false, true]; 128 | } 129 | } 130 | 131 | return [true, true]; 132 | } 133 | 134 | /** 135 | * @param array $tokens 136 | * @param int $from 137 | * @return array 138 | */ 139 | protected function checkIsFunctionCall(array $tokens, $from) 140 | { 141 | $arguments = []; 142 | 143 | $count = 0; 144 | $argumentFrom = 0; 145 | 146 | for ($i = $from + 1; $i < count($tokens); $i++) { 147 | if ($tokens[$i] === '(') { 148 | $count++; 149 | if ($count === 1) { 150 | $argumentFrom = $i + 1; 151 | } 152 | } else if ($tokens[$i] === ')') { 153 | if (--$count === 0) { 154 | $arguments[] = new FunctionArgument(array_slice($tokens, $argumentFrom, $i - $argumentFrom)); 155 | return [true, $arguments]; 156 | } 157 | } else if ($tokens[$i] === ',' && $count === 1) { 158 | $arguments[] = new FunctionArgument(array_slice($tokens, $argumentFrom, $i - $argumentFrom)); 159 | $argumentFrom = $i + 1; 160 | } 161 | } 162 | 163 | return [false, $arguments]; 164 | } 165 | 166 | /** 167 | * @param string $content 168 | * @return array 169 | */ 170 | protected function tokenize($content) 171 | { 172 | $tokens = token_get_all($content); 173 | $tokens = array_values(array_filter($tokens, function ($token) { 174 | return !is_array($token) || $token[0] !== T_WHITESPACE; 175 | })); 176 | 177 | return $tokens; 178 | } 179 | 180 | /** 181 | * @param array $functionsToCheck 182 | * @return array 183 | */ 184 | protected function prepareFunctionCheck(array $functionsToCheck) 185 | { 186 | $output = []; 187 | 188 | foreach ($functionsToCheck as $function) { 189 | $namespaces = explode('\\', $function); 190 | 191 | $next = &$output; 192 | 193 | foreach ($namespaces as $key => $namespace) { 194 | if (strpos($namespace, '::') !== false) { 195 | list($first, $second) = explode('::', $namespace); 196 | 197 | if (!isset($next[$first])) { 198 | $next[$first] = []; 199 | } 200 | $next = &$next[$first]; 201 | 202 | if (!isset($next[T_DOUBLE_COLON])) { 203 | $next[T_DOUBLE_COLON] = []; 204 | } 205 | $next = &$next[T_DOUBLE_COLON]; 206 | 207 | if (!isset($next[$second])) { 208 | $next[$second] = []; 209 | } 210 | $next = &$next[$second]; 211 | } else if (!empty($namespace)) { 212 | if (!isset($next[$namespace])) { 213 | $next[$namespace] = []; 214 | } 215 | $next = &$next[$namespace]; 216 | 217 | if (isset($namespaces[$key + 1])) { 218 | if (!isset($next[T_NS_SEPARATOR])) { 219 | $next[T_NS_SEPARATOR] = []; 220 | } 221 | $next = &$next[T_NS_SEPARATOR]; 222 | } 223 | } else { 224 | if (!isset($next[T_NS_SEPARATOR])) { 225 | $next[T_NS_SEPARATOR] = []; 226 | } 227 | $next = &$next[T_NS_SEPARATOR]; 228 | } 229 | } 230 | } 231 | 232 | return $output; 233 | } 234 | } 235 | 236 | 237 | -------------------------------------------------------------------------------- /src/Exception/Exception.php: -------------------------------------------------------------------------------- 1 | argument = $argument; 12 | } 13 | 14 | /** 15 | * @return string 16 | */ 17 | public function getArgument() 18 | { 19 | return $this->argument; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Exception/NotExistsPath.php: -------------------------------------------------------------------------------- 1 | path = $path; 15 | $this->message = "Path '$path' not found"; 16 | } 17 | 18 | /** 19 | * @return string 20 | */ 21 | public function getPath() 22 | { 23 | return $this->path; 24 | } 25 | } -------------------------------------------------------------------------------- /src/FunctionArgument.php: -------------------------------------------------------------------------------- 1 | tokens = $tokens; 12 | } 13 | 14 | /** 15 | * @return array 16 | */ 17 | public function isTrue() 18 | { 19 | $sure = true; 20 | $prediction = null; 21 | 22 | for ($i = 0; $i < count($this->tokens); $i++) { 23 | if (is_array($this->tokens[$i])) { 24 | list($tokenType, $token) = $this->tokens[$i]; 25 | $token = strtolower($token); 26 | if ($tokenType === T_COMMENT) { 27 | continue; 28 | } else if ($tokenType === T_STRING && in_array($token, ['true', 'false', 'null'])) { 29 | if ($token === 'true') { 30 | $prediction = true; 31 | } else { 32 | $prediction = false; 33 | } 34 | } else if ($tokenType === T_LNUMBER) { 35 | $prediction = $token !== '0'; 36 | } else if ($tokenType === T_DNUMBER) { 37 | $prediction = $token !== '0.0'; 38 | } else if ($tokenType === T_VARIABLE) { 39 | $skipTo = $this->skipVariableAssign($i + 1); 40 | if ($skipTo === false) { 41 | $sure = false; 42 | } else { 43 | $i = $skipTo; 44 | } 45 | } else { 46 | $sure = false; 47 | } 48 | } else { 49 | $sure = false; 50 | } 51 | } 52 | 53 | return [$prediction, $sure]; 54 | } 55 | 56 | /** 57 | * @param int $from 58 | * @return bool 59 | */ 60 | protected function skipVariableAssign($from) 61 | { 62 | for ($i = $from; $i < count($this->tokens); $i++) { 63 | if (is_array($this->tokens[$i])) { 64 | list($tokenType) = $this->tokens[$i]; 65 | if ($tokenType === T_COMMENT) { 66 | continue; 67 | } 68 | } else if ($this->tokens[$i] === '=') { 69 | return $i; 70 | } else { 71 | return false; 72 | } 73 | } 74 | 75 | return false; 76 | } 77 | } -------------------------------------------------------------------------------- /src/FunctionConditions.php: -------------------------------------------------------------------------------- 1 | argumentNumber = $argumentNumber; 23 | $this->mustBe = $mustBe; 24 | $this->default = $default; 25 | } 26 | 27 | /** 28 | * @return int 29 | */ 30 | public function getArgumentNumber() 31 | { 32 | return $this->argumentNumber; 33 | } 34 | 35 | /** 36 | * @return boolean 37 | */ 38 | public function getDefault() 39 | { 40 | return $this->default; 41 | } 42 | 43 | /** 44 | * @return boolean 45 | */ 46 | public function getMustBe() 47 | { 48 | return $this->mustBe; 49 | } 50 | } -------------------------------------------------------------------------------- /src/Manager.php: -------------------------------------------------------------------------------- 1 | getFilesFromPaths($settings->paths, $settings->extensions, $settings->excluded); 15 | $checkedFiles = count($files); 16 | 17 | $output = $output ?: ($settings->colors ? new OutputColored(new Writer\Console) : new Output(new Writer\Console)); 18 | $output->setTotalFileCount($checkedFiles); 19 | 20 | /** @var Result[] $results */ 21 | $results = []; 22 | 23 | $startTime = microtime(true); 24 | $checkedFiles = 0; 25 | $filesWithDump = 0; 26 | 27 | foreach ($files as $file) { 28 | try { 29 | $fileResult = $this->checkFile($file, $settings); 30 | $checkedFiles++; 31 | 32 | if (empty($fileResult)) { 33 | $output->ok(); 34 | } else { 35 | $output->error(); 36 | $filesWithDump++; 37 | } 38 | 39 | $results = array_merge($results, $fileResult); 40 | } catch (Exception\Exception $e) { 41 | $output->fail(); 42 | } 43 | } 44 | 45 | $runTime = round(microtime(true) - $startTime, 1); 46 | 47 | $output->writeNewLine(2); 48 | 49 | $message = "Checked $checkedFiles files in $runTime second, "; 50 | if ($filesWithDump === 0) { 51 | $message .= "no dump found."; 52 | } else { 53 | $message .= "dump found in $filesWithDump "; 54 | $message .= ($filesWithDump === 1 ? 'file' : 'files'); 55 | } 56 | 57 | $output->writeLine($message); 58 | 59 | if (!empty($results)) { 60 | $output->writeNewLine(); 61 | 62 | foreach ($results as $result) { 63 | $output->writeLine(str_repeat('-', 60)); 64 | $output->writeResult($result); 65 | } 66 | 67 | return false; 68 | } 69 | 70 | 71 | return true; 72 | } 73 | 74 | /** 75 | * @param string $filename 76 | * @param Settings $settings 77 | * @return Result[] 78 | * @throws Exception\FileNotFound 79 | * @throws Exception\FileOpen 80 | */ 81 | public function checkFile($filename, Settings $settings = null) 82 | { 83 | if ($settings === null) { 84 | $settings = new Settings(); 85 | } 86 | 87 | $content = $this->loadFile($filename); 88 | 89 | $checker = new Checker($settings); 90 | $results = $checker->check($content); 91 | $this->setFilePathToResults($results, $filename); 92 | 93 | return $results; 94 | } 95 | 96 | /** 97 | * @param string $filename 98 | * @return string 99 | * @throws Exception\FileOpen 100 | * @throws Exception\FileNotFound 101 | */ 102 | protected function loadFile($filename) 103 | { 104 | if (!file_exists($filename)) { 105 | throw new Exception\FileNotFound("File '$filename' was not found.'"); 106 | } 107 | 108 | $content = file_get_contents($filename); 109 | 110 | if ($content === false) { 111 | throw new Exception\FileOpen("Can not open file '$filename'."); 112 | } 113 | 114 | return $content; 115 | } 116 | 117 | /** 118 | * @param array $paths 119 | * @param array $extensions 120 | * @param array $excluded 121 | * @return array 122 | * @throws Exception\NotExistsPath 123 | */ 124 | protected function getFilesFromPaths(array $paths, array $extensions, array $excluded = []) 125 | { 126 | $extensions = array_flip($extensions); 127 | $files = []; 128 | 129 | foreach ($paths as $path) { 130 | if (is_file($path)) { 131 | $files[] = $path; 132 | } else if (is_dir($path)) { 133 | $iterator = new \RecursiveDirectoryIterator($path); 134 | if (!empty($excluded)) { 135 | $iterator = new RecursiveDirectoryFilterIterator($iterator, $excluded); 136 | } 137 | $iterator = new \RecursiveIteratorIterator($iterator); 138 | 139 | /** @var \SplFileInfo[] $iterator */ 140 | foreach ($iterator as $directoryFile) { 141 | if (isset($extensions[pathinfo($directoryFile->getFilename(), PATHINFO_EXTENSION)])) { 142 | $files[] = (string) $directoryFile; 143 | } 144 | } 145 | } else { 146 | throw new Exception\NotExistsPath($path); 147 | } 148 | } 149 | 150 | return $files; 151 | } 152 | 153 | /** 154 | * @param Result[] $results 155 | * @param string $filePath 156 | */ 157 | protected function setFilePathToResults(array $results, $filePath) 158 | { 159 | foreach ($results as $result) { 160 | $result->setFilePath($filePath); 161 | } 162 | } 163 | } -------------------------------------------------------------------------------- /src/Output.php: -------------------------------------------------------------------------------- 1 | writer = $writer ?: new Writer\Console; 24 | } 25 | 26 | public function ok() 27 | { 28 | $this->writer->write('.'); 29 | $this->progress(); 30 | } 31 | 32 | public function error() 33 | { 34 | $this->writer->write('X'); 35 | $this->progress(); 36 | } 37 | 38 | public function fail() 39 | { 40 | $this->writer->write('-'); 41 | $this->progress(); 42 | } 43 | 44 | /** 45 | * @param string|null $line 46 | */ 47 | public function writeLine($line = null) 48 | { 49 | $this->writer->write($line . PHP_EOL); 50 | } 51 | 52 | /** 53 | * @param int $count 54 | */ 55 | public function writeNewLine($count = 1) 56 | { 57 | $this->writer->write(str_repeat(PHP_EOL, $count)); 58 | } 59 | 60 | /** 61 | * @param int $count 62 | */ 63 | public function setTotalFileCount($count) 64 | { 65 | $this->totalFileCount = $count; 66 | } 67 | 68 | /** 69 | * @param Result $result 70 | * @param bool $withCodeSnippet 71 | */ 72 | public function writeResult(Result $result, $withCodeSnippet = true) 73 | { 74 | $string = "Forgotten dump '{$result->getType()}' found in {$result->getShortFilePath()}:{$result->getLineNumber()}" . PHP_EOL; 75 | 76 | if ($withCodeSnippet) { 77 | $string .= $this->getCodeSnippet(file_get_contents($result->getFilePath()), $result->getLineNumber()); 78 | } 79 | 80 | $this->writer->write($string); 81 | } 82 | 83 | /** 84 | * @param string $fileContent 85 | * @param int $lineNumber 86 | * @param int $linesBefore 87 | * @param int $linesAfter 88 | * @return string 89 | */ 90 | protected function getCodeSnippet($fileContent, $lineNumber, $linesBefore = 2, $linesAfter = 2) 91 | { 92 | $lines = explode("\n", $fileContent); 93 | 94 | $offset = $lineNumber - $linesBefore - 1; 95 | $offset = max($offset, 0); 96 | $length = $linesAfter + $linesBefore + 1; 97 | $lines = array_slice($lines, $offset, $length, $preserveKeys = true); 98 | 99 | end($lines); 100 | $lineStrlen = strlen(key($lines) + 1); 101 | 102 | $snippet = ''; 103 | foreach ($lines as $i => $line) { 104 | $snippet .= ($lineNumber === $i + 1 ? ' > ' : ' '); 105 | $snippet .= str_pad($i + 1, $lineStrlen, ' ', STR_PAD_LEFT) . '| ' . rtrim($line) . PHP_EOL; 106 | } 107 | 108 | return $snippet; 109 | } 110 | 111 | protected function progress() 112 | { 113 | if (++$this->checkedFiles % $this->filesPerLine === 0) { 114 | if ($this->totalFileCount != 0) { // != 115 | $percent = round($this->checkedFiles / $this->totalFileCount * 100); 116 | $current = $this->stringWidth($this->checkedFiles, strlen($this->totalFileCount)); 117 | $this->writeLine(" $current/$this->totalFileCount ($percent %)"); 118 | } 119 | } 120 | } 121 | 122 | /** 123 | * @param string $input 124 | * @param int $width 125 | * @return string 126 | */ 127 | protected function stringWidth($input, $width = 3) 128 | { 129 | $multiplier = $width - strlen($input); 130 | return str_repeat(' ', $multiplier > 0 ? $multiplier : 0) . $input; 131 | } 132 | } -------------------------------------------------------------------------------- /src/OutputColored.php: -------------------------------------------------------------------------------- 1 | color = new Color(); 24 | } 25 | 26 | if (!$highlighter && $this->color && class_exists('\JakubOnderka\PhpConsoleHighlighter\Highlighter')) { 27 | $this->highlighter = new Highlighter($this->color); 28 | } 29 | } 30 | 31 | public function error() 32 | { 33 | if ($this->color) { 34 | $this->writer->write($this->color->apply('bg_red', 'X')); 35 | $this->progress(); 36 | } else { 37 | parent::error(); 38 | } 39 | } 40 | 41 | /** 42 | * @param string $fileContent 43 | * @param int $lineNumber 44 | * @param int $linesBefore 45 | * @param int $linesAfter 46 | * @return string 47 | */ 48 | protected function getCodeSnippet($fileContent, $lineNumber, $linesBefore = 2, $linesAfter = 2) 49 | { 50 | if ($this->highlighter) { 51 | return $this->highlighter->getCodeSnippet($fileContent, $lineNumber, $linesBefore, $linesAfter); 52 | } else { 53 | return parent::getCodeSnippet($fileContent, $lineNumber, $linesBefore, $linesAfter); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/RecursiveDirectoryFilterIterator.php: -------------------------------------------------------------------------------- 1 | iterator = $iterator; 20 | $this->excluded = array_map([$this, 'getPathname'], $excluded); 21 | } 22 | 23 | /** 24 | * (PHP 5 >= 5.1.0)
25 | * Check whether the current element of the iterator is acceptable 26 | * 27 | * @link http://php.net/manual/en/filteriterator.accept.php 28 | * @return bool true if the current element is acceptable, otherwise false. 29 | */ 30 | #[\ReturnTypeWillChange] 31 | public function accept() 32 | { 33 | $current = $this->current()->getPathname(); 34 | $current = $this->normalizeDirectorySeparator($current); 35 | 36 | if ('.' . DIRECTORY_SEPARATOR !== $current[0] . $current[1]) { 37 | $current = '.' . DIRECTORY_SEPARATOR . $current; 38 | } 39 | 40 | return !in_array($current, $this->excluded); 41 | } 42 | 43 | /** 44 | * (PHP 5 >= 5.1.0)
45 | * Check whether the inner iterator's current element has children 46 | * 47 | * @link http://php.net/manual/en/recursivefilteriterator.haschildren.php 48 | * @return bool true if the inner iterator has children, otherwise false 49 | */ 50 | #[\ReturnTypeWillChange] 51 | public function hasChildren() 52 | { 53 | return $this->iterator->hasChildren(); 54 | } 55 | 56 | /** 57 | * (PHP 5 >= 5.1.0)
58 | * Return the inner iterator's children contained in a RecursiveFilterIterator 59 | * 60 | * @link http://php.net/manual/en/recursivefilteriterator.getchildren.php 61 | * @return \RecursiveFilterIterator containing the inner iterator's children. 62 | */ 63 | #[\ReturnTypeWillChange] 64 | public function getChildren() 65 | { 66 | return new self($this->iterator->getChildren(), $this->excluded); 67 | } 68 | 69 | /** 70 | * @param string $file 71 | * @return string 72 | */ 73 | private function getPathname($file) 74 | { 75 | $file = $this->normalizeDirectorySeparator($file); 76 | 77 | if ('.' . DIRECTORY_SEPARATOR !== $file[0] . $file[1]) { 78 | $file = '.' . DIRECTORY_SEPARATOR . $file; 79 | } 80 | 81 | $directoryFile = new \SplFileInfo($file); 82 | return $directoryFile->getPathname(); 83 | } 84 | 85 | /** 86 | * @param string $file 87 | * @return string 88 | */ 89 | private function normalizeDirectorySeparator($file) 90 | { 91 | return str_replace(['\\', '/'], DIRECTORY_SEPARATOR, $file); 92 | } 93 | } -------------------------------------------------------------------------------- /src/Result.php: -------------------------------------------------------------------------------- 1 | type = $type; 26 | $this->lineNumber = $lineNumber; 27 | $this->sure = $sure; 28 | } 29 | 30 | /** 31 | * @param string $filePath 32 | */ 33 | public function setFilePath($filePath) 34 | { 35 | $this->filePath = $filePath; 36 | } 37 | 38 | /** 39 | * @return string 40 | */ 41 | public function getType() 42 | { 43 | return $this->type; 44 | } 45 | 46 | /** 47 | * @return int 48 | */ 49 | public function getLineNumber() 50 | { 51 | return $this->lineNumber; 52 | } 53 | 54 | /** 55 | * @return bool 56 | */ 57 | public function isSure() 58 | { 59 | return $this->sure; 60 | } 61 | 62 | /** 63 | * @return string 64 | */ 65 | public function getFilePath() 66 | { 67 | return $this->filePath; 68 | } 69 | 70 | /** 71 | * @return string 72 | */ 73 | public function getShortFilePath() 74 | { 75 | return str_replace(getcwd(), '', $this->filePath); 76 | } 77 | } -------------------------------------------------------------------------------- /src/Settings.php: -------------------------------------------------------------------------------- 1 | paths[] = $argument; 82 | } else { 83 | switch ($argument) { 84 | case '--extensions': 85 | $setting->extensions = array_map('trim', explode(',', $arguments->getNext())); 86 | break; 87 | 88 | case '--exclude': 89 | $setting->excluded[] = $arguments->getNext(); 90 | break; 91 | 92 | case '--no-colors': 93 | $setting->colors = false; 94 | break; 95 | 96 | case '--tracy': 97 | $setting->functionsToCheck[] = self::DEBUGGER_DUMP; 98 | $setting->functionsToCheck[] = self::DEBUGGER_DUMP_SHORTCUT; 99 | $setting->functionsToCheck[] = self::DEBUGGER_BARDUMP; 100 | $setting->functionsToCheck[] = self::DEBUGGER_BARDUMP_SHORTCUT; 101 | break; 102 | 103 | case '--zend': 104 | $setting->functionsToCheck[] = self::ZEND_DEBUG_DUMP; 105 | $setting->functionsToCheck[] = self::ZEND_DEBUG_DUMP_2; 106 | break; 107 | 108 | case '--ladybug': 109 | $setting->functionsToCheck[] = self::LADYBUG_DUMP; 110 | $setting->functionsToCheck[] = self::LADYBUG_DUMP_DIE; 111 | $setting->functionsToCheck[] = self::LADYBUG_DUMP_SHORTCUT; 112 | $setting->functionsToCheck[] = self::LADYBUG_DUMP_DIE_SHORTCUT; 113 | break; 114 | 115 | case '--symfony': 116 | $setting->functionsToCheck[] = self::SYMFONY_VARDUMPER_DUMP; 117 | $setting->functionsToCheck[] = self::SYMFONY_VARDUMPER_DUMP_SHORTCUT; 118 | $setting->functionsToCheck[] = self::SYMFONY_VARDUMPER_DD; 119 | $setting->functionsToCheck[] = self::SYMFONY_VARDUMPER_DD_SHORTCUT; 120 | $setting->functionsToCheck[] = self::SYMFONY_VARDUMPER_HANDLER; 121 | break; 122 | 123 | case '--laravel': 124 | $setting->functionsToCheck[] = self::LARAVEL_DUMP_DD; 125 | $setting->functionsToCheck[] = self::LARAVEL_DUMP; 126 | break; 127 | 128 | case '--custom-function': 129 | $customFunctions = array_map('trim', explode(',', $arguments->getNext())); 130 | break; 131 | 132 | case '--doctrine': 133 | $setting->functionsToCheck[] = self::DOCTRINE_DUMP; 134 | $setting->functionsToCheck[] = self::DOCTRINE_DUMP_2; 135 | break; 136 | 137 | default: 138 | throw new Exception\InvalidArgument($argument); 139 | } 140 | } 141 | } 142 | 143 | // Merge if any custom function is given 144 | $setting->functionsToCheck = array_merge($setting->functionsToCheck, $customFunctions); 145 | $setting->functionsToCheck = array_unique($setting->functionsToCheck); 146 | 147 | return $setting; 148 | } 149 | 150 | /** 151 | * @param string $method 152 | * @return FunctionConditions 153 | */ 154 | public function getFunctionCondition($method) 155 | { 156 | $functionConditions = [ 157 | self::VAR_DUMP => new FunctionConditions(2, false, false), 158 | self::PRINT_R => new FunctionConditions(2, false, false), 159 | self::VAR_EXPORT => new FunctionConditions(2, false, false), 160 | self::ZEND_DEBUG_DUMP => new FunctionConditions(3, true, true), 161 | self::DEBUGGER_DUMP => new FunctionConditions(2, false, false), 162 | self::DOCTRINE_DUMP => new FunctionConditions(2, false, false), 163 | ]; 164 | 165 | 166 | if (!isset($functionConditions[$method])) { 167 | return null; 168 | } 169 | 170 | return $functionConditions[$method]; 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/Writer/Console.php: -------------------------------------------------------------------------------- 1 | logFile = $logFile; 18 | } 19 | 20 | /** 21 | * @param string $string 22 | */ 23 | public function write($string) 24 | { 25 | $this->buffer .= $string; 26 | } 27 | 28 | public function __destruct() 29 | { 30 | file_put_contents($this->logFile, $this->buffer); 31 | } 32 | } -------------------------------------------------------------------------------- /src/Writer/Multiple.php: -------------------------------------------------------------------------------- 1 | addWriter($writer); 16 | } 17 | } 18 | 19 | /** 20 | * @param Writer $writer 21 | */ 22 | public function addWriter(Writer $writer) 23 | { 24 | $this->writers[] = $writer; 25 | } 26 | 27 | /** 28 | * @param string $string 29 | */ 30 | public function write($string) 31 | { 32 | foreach ($this->writers as $writer) { 33 | $writer->write($string); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/Writer/Writer.php: -------------------------------------------------------------------------------- 1 | 17 | Options: 18 | --tracy Enable support for Tracy (Debugger::dump) 19 | --zend Enable support for Zend (Zend_Debug::dump and \Zend\Debug\Debug::dump) 20 | --ladybug Enable support for Ladybug (ladybug_dump, ladybug_dump_die, ld, ldd) 21 | --symfony Enable support for Symfony2 (dump, VarDumper::dump, VarDumper::setHandler, Vardumper::dd()) 22 | --doctrine Enable support for Doctrine (Doctrine::dump, \Doctrine\Common\Util\Debug::dump) 23 | --laravel Enable support for Laravel (dd, dump) 24 | --custom-function Comma separated custom function name(s) to check like "pre_echo". 25 | --extensions Check only files with selected extensions separated by comma 26 | (default: php, php3, php4, php5, phtml) 27 | --exclude Exclude directory. If you want exclude multiple directory, use 28 | multiple exclude parameters. 29 | --no-colors Disable colors in console output. 30 | -V, --version Show version. 31 | -h, --help Print this help. 32 | 37 | PHP Var Dump check version 38 | --------------------------- 39 | Usage: 40 | var-dump-check [files or directories] 41 | getArgument()}" . PHP_EOL); 79 | echo PHP_EOL; 80 | showOptions(); 81 | die(FAILED); 82 | } 83 | 84 | try { 85 | $check = new PhpVarDumpCheck\Manager(); 86 | $status = $check->check($settings); 87 | die($status ? SUCCESS : WITH_ERRORS); 88 | } catch (PhpVarDumpCheck\Exception\Exception $e) { 89 | fwrite(STDERR, $e->getMessage() . PHP_EOL); 90 | die(FAILED); 91 | } 92 | --------------------------------------------------------------------------------