PHP_CodeSniffer
[ class tree: PHP_CodeSniffer ] [ index: PHP_CodeSniffer ] [ all elements ]

Source for file Cache.php

Documentation is available at Cache.php

  1. <?php
  2. /**
  3.  * Function for caching between runs.
  4.  *
  5.  * @author    Greg Sherwood <gsherwood@squiz.net>
  6.  * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
  7.  * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  8.  */
  9.  
  10. namespace PHP_CodeSniffer\Util;
  11.  
  12. use PHP_CodeSniffer\Autoload;
  13. use PHP_CodeSniffer\Config;
  14. use PHP_CodeSniffer\Ruleset;
  15. use PHP_CodeSniffer\Util\Common;
  16.  
  17. class Cache
  18. {
  19.  
  20.     /**
  21.      * The filesystem location of the cache file.
  22.      *
  23.      * @var void 
  24.      */
  25.     private static $path = '';
  26.  
  27.     /**
  28.      * The cached data.
  29.      *
  30.      * @var array<string, mixed>
  31.      */
  32.     private static $cache = array();
  33.  
  34.  
  35.     /**
  36.      * Loads existing cache data for the run, if any.
  37.      *
  38.      * @param \PHP_CodeSniffer\Ruleset $ruleset The ruleset used for the run.
  39.      * @param \PHP_CodeSniffer\Config  $config  The config data for the run.
  40.      *
  41.      * @return void 
  42.      */
  43.     public static function load(Ruleset $ruleset, Config $config)
  44.     {
  45.         // Look at every loaded sniff class so far and use their file contents
  46.         // to generate a hash for the code used during the run.
  47.         // At this point, the loaded class list contains the core PHPCS code
  48.         // and all sniffs that have been loaded as part of the run.
  49.         if (PHP_CODESNIFFER_VERBOSITY > 1) {
  50.             echo PHP_EOL."\tGenerating loaded file list for code hash".PHP_EOL;
  51.         }
  52.  
  53.         $codeHash = '';
  54.         $classes  = array_keys(Autoload::getLoadedClasses());
  55.         sort($classes);
  56.  
  57.         $installDir     = dirname(__DIR__);
  58.         $installDirLen  = strlen($installDir);
  59.         $standardDir    = $installDir.DIRECTORY_SEPARATOR.'Standards';
  60.         $standardDirLen = strlen($standardDir);
  61.         foreach ($classes as $file) {
  62.             if (substr($file, 0, $standardDirLen) !== $standardDir) {
  63.                 if (substr($file, 0, $installDirLen) === $installDir) {
  64.                     // We are only interested in sniffs here.
  65.                     continue;
  66.                 }
  67.  
  68.                 if (PHP_CODESNIFFER_VERBOSITY > 1) {
  69.                     echo "\t\t=> external file: $file".PHP_EOL;
  70.                 }
  71.             } else if (PHP_CODESNIFFER_VERBOSITY > 1) {
  72.                 echo "\t\t=> internal sniff: $file".PHP_EOL;
  73.             }
  74.  
  75.             $codeHash .= md5_file($file);
  76.         }
  77.  
  78.         // Add the content of the used rulesets to the hash so that sniff setting
  79.         // changes in the ruleset invalidate the cache.
  80.         $rulesets = $ruleset->paths;
  81.         sort($rulesets);
  82.         foreach ($rulesets as $file) {
  83.             if (substr($file, 0, $standardDirLen) !== $standardDir) {
  84.                 if (PHP_CODESNIFFER_VERBOSITY > 1) {
  85.                     echo "\t\t=> external ruleset: $file".PHP_EOL;
  86.                 }
  87.             } else if (PHP_CODESNIFFER_VERBOSITY > 1) {
  88.                 echo "\t\t=> internal ruleset: $file".PHP_EOL;
  89.             }
  90.  
  91.             $codeHash .= md5_file($file);
  92.         }
  93.  
  94.         // Go through the core PHPCS code and add those files to the file
  95.         // hash. This ensures that core PHPCS changes will also invalidate the cache.
  96.         // Note that we ignore sniffs here, and any files that don't affect
  97.         // the outcome of the run.
  98.         $di = new \RecursiveIteratorIterator(
  99.             new \RecursiveDirectoryIterator($installDir),
  100.             0,
  101.             \RecursiveIteratorIterator::CATCH_GET_CHILD
  102.         );
  103.  
  104.         $di     = new \RecursiveDirectoryIterator($installDir);
  105.         $filter = new \RecursiveCallbackFilterIterator(
  106.             $di,
  107.             function ($file, $key, $iterator) {
  108.                 // Skip hidden files.
  109.                 $filename = $file->getFilename();
  110.                 if (substr($filename, 0, 1) === '.') {
  111.                     return false;
  112.                 }
  113.  
  114.                 $filePath = Common::realpath($file->getPathname());
  115.                 if ($filePath === false) {
  116.                     return false;
  117.                 }
  118.  
  119.                 if (is_dir($filePath) === true
  120.                     && ($filename === 'Standards'
  121.                     || $filename === 'Exceptions'
  122.                     || $filename === 'Reports'
  123.                     || $filename === 'Generators')
  124.                 ) {
  125.                     return false;
  126.                 }
  127.  
  128.                 return true;
  129.             }
  130.         );
  131.  
  132.         $iterator = new \RecursiveIteratorIterator($filter);
  133.         foreach ($iterator as $file) {
  134.             if (PHP_CODESNIFFER_VERBOSITY > 1) {
  135.                 echo "\t\t=> core file: $file".PHP_EOL;
  136.             }
  137.  
  138.             $codeHash .= md5_file($file);
  139.         }
  140.  
  141.         $codeHash = md5($codeHash);
  142.  
  143.         // Along with the code hash, use various settings that can affect
  144.         // the results of a run to create a new hash. This hash will be used
  145.         // in the cache file name.
  146.         $rulesetHash = md5(var_export($ruleset->ignorePatterns, true).var_export($ruleset->includePatterns, true));
  147.         $configData  = array(
  148.                         'tabWidth'     => $config->tabWidth,
  149.                         'encoding'     => $config->encoding,
  150.                         'recordErrors' => $config->recordErrors,
  151.                         'annotations'  => $config->annotations,
  152.                         'codeHash'     => $codeHash,
  153.                         'rulesetHash'  => $rulesetHash,
  154.                        );
  155.  
  156.         $configString = implode(',', $configData);
  157.         $cacheHash    = substr(sha1($configString), 0, 12);
  158.  
  159.         if (PHP_CODESNIFFER_VERBOSITY > 1) {
  160.             echo "\tGenerating cache key data".PHP_EOL;
  161.             echo "\t\t=> tabWidth: ".$configData['tabWidth'].PHP_EOL;
  162.             echo "\t\t=> encoding: ".$configData['encoding'].PHP_EOL;
  163.             echo "\t\t=> recordErrors: ".(int) $configData['recordErrors'].PHP_EOL;
  164.             echo "\t\t=> annotations: ".(int) $configData['annotations'].PHP_EOL;
  165.             echo "\t\t=> codeHash: ".$configData['codeHash'].PHP_EOL;
  166.             echo "\t\t=> rulesetHash: ".$configData['rulesetHash'].PHP_EOL;
  167.             echo "\t\t=> cacheHash: $cacheHash".PHP_EOL;
  168.         }
  169.  
  170.         if ($config->cacheFile !== null) {
  171.             $cacheFile = $config->cacheFile;
  172.         } else {
  173.             // Determine the common paths for all files being checked.
  174.             // We can use this to locate an existing cache file, or to
  175.             // determine where to create a new one.
  176.             if (PHP_CODESNIFFER_VERBOSITY > 1) {
  177.                 echo "\tChecking possible cache file paths".PHP_EOL;
  178.             }
  179.  
  180.             $paths = array();
  181.             foreach ($config->files as $file) {
  182.                 $file = Common::realpath($file);
  183.                 while ($file !== DIRECTORY_SEPARATOR) {
  184.                     if (isset($paths[$file]) === false) {
  185.                         $paths[$file] = 1;
  186.                     } else {
  187.                         $paths[$file]++;
  188.                     }
  189.  
  190.                     $lastFile = $file;
  191.                     $file     = dirname($file);
  192.                     if ($file === $lastFile) {
  193.                         // Just in case something went wrong,
  194.                         // we don't want to end up in an infinite loop.
  195.                         break;
  196.                     }
  197.                 }
  198.             }
  199.  
  200.             ksort($paths);
  201.             $paths = array_reverse($paths);
  202.  
  203.             $numFiles  = count($config->files);
  204.             $tmpDir    = sys_get_temp_dir();
  205.             $cacheFile = null;
  206.             foreach ($paths as $file => $count) {
  207.                 if ($count !== $numFiles) {
  208.                     unset($paths[$file]);
  209.                     continue;
  210.                 }
  211.  
  212.                 $fileHash = substr(sha1($file), 0, 12);
  213.                 $testFile = $tmpDir.DIRECTORY_SEPARATOR."phpcs.$fileHash.$cacheHash.cache";
  214.                 if ($cacheFile === null) {
  215.                     // This will be our default location if we can't find
  216.                     // an existing file.
  217.                     $cacheFile = $testFile;
  218.                 }
  219.  
  220.                 if (PHP_CODESNIFFER_VERBOSITY > 1) {
  221.                     echo "\t\t=> $testFile".PHP_EOL;
  222.                     echo "\t\t\t * based on shared location: $file *".PHP_EOL;
  223.                 }
  224.  
  225.                 if (file_exists($testFile) === true) {
  226.                     $cacheFile = $testFile;
  227.                     break;
  228.                 }
  229.             }//end foreach
  230.  
  231.             if ($cacheFile === null) {
  232.                 // Unlikely, but just in case $paths is empty for some reason.
  233.                 $cacheFile = $tmpDir.DIRECTORY_SEPARATOR."phpcs.$cacheHash.cache";
  234.             }
  235.         }//end if
  236.  
  237.         self::$path = $cacheFile;
  238.         if (PHP_CODESNIFFER_VERBOSITY > 1) {
  239.             echo "\t=> Using cache file: ".self::$path.PHP_EOL;
  240.         }
  241.  
  242.         if (file_exists(self::$path) === true) {
  243.             self::$cache = json_decode(file_get_contents(self::$path), true);
  244.  
  245.             // Verify the contents of the cache file.
  246.             if (self::$cache['config'] !== $configData) {
  247.                 self::$cache = array();
  248.                 if (PHP_CODESNIFFER_VERBOSITY > 1) {
  249.                     echo "\t* cache was invalid and has been cleared *".PHP_EOL;
  250.                 }
  251.             }
  252.         } else if (PHP_CODESNIFFER_VERBOSITY > 1) {
  253.             echo "\t* cache file does not exist *".PHP_EOL;
  254.         }
  255.  
  256.         self::$cache['config'] = $configData;
  257.  
  258.     }//end load()
  259.  
  260.  
  261.     /**
  262.      * Saves the current cache to the filesystem.
  263.      *
  264.      * @return void 
  265.      */
  266.     public static function save()
  267.     {
  268.         file_put_contents(self::$path, json_encode(self::$cache));
  269.  
  270.     }//end save()
  271.  
  272.  
  273.     /**
  274.      * Retrieves a single entry from the cache.
  275.      *
  276.      * @param string $key The key of the data to get. If NULL,
  277.      *                     everything in the cache is returned.
  278.      *
  279.      * @return mixed 
  280.      */
  281.     public static function get($key=null)
  282.     {
  283.         if ($key === null) {
  284.             return self::$cache;
  285.         }
  286.  
  287.         if (isset(self::$cache[$key]) === true) {
  288.             return self::$cache[$key];
  289.         }
  290.  
  291.         return false;
  292.  
  293.     }//end get()
  294.  
  295.  
  296.     /**
  297.      * Retrieves a single entry from the cache.
  298.      *
  299.      * @param string $key   The key of the data to set. If NULL,
  300.      *                       sets the entire cache.
  301.      * @param mixed  $value The value to set.
  302.      *
  303.      * @return void 
  304.      */
  305.     public static function set($key, $value)
  306.     {
  307.         if ($key === null) {
  308.             self::$cache = $value;
  309.         } else {
  310.             self::$cache[$key] = $value;
  311.         }
  312.  
  313.     }//end set()
  314.  
  315.  
  316.     /**
  317.      * Retrieves the number of cache entries.
  318.      *
  319.      * @return int 
  320.      */
  321.     public static function getSize()
  322.     {
  323.         return (count(self::$cache) - 1);
  324.  
  325.     }//end getSize()
  326.  
  327.  
  328. }//end class

Documentation generated on Mon, 11 Mar 2019 15:27:15 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.