Skip to content

Commit

Permalink
Merge 34b61cd into cbcf363
Browse files Browse the repository at this point in the history
  • Loading branch information
jrfnl committed Jun 29, 2022
2 parents cbcf363 + 34b61cd commit 756d8fc
Show file tree
Hide file tree
Showing 22 changed files with 1,876 additions and 16 deletions.
9 changes: 8 additions & 1 deletion .github/workflows/quicktest.yml
Expand Up @@ -74,7 +74,14 @@ jobs:
if: matrix.phpcs_version == 'dev-master'
run: composer lint

- name: Run the unit tests
- name: Run the unit tests without caching
run: vendor/bin/phpunit --no-coverage
env:
PHPCS_VERSION: ${{ matrix.phpcs_version }}
PHPCSUTILS_USE_CACHE: false

- name: Run the unit tests with caching
run: vendor/bin/phpunit --testsuite PHPCSUtils --no-coverage --repeat 2
env:
PHPCS_VERSION: ${{ matrix.phpcs_version }}
PHPCSUTILS_USE_CACHE: true
16 changes: 13 additions & 3 deletions .github/workflows/test.yml
Expand Up @@ -189,11 +189,19 @@ jobs:
with:
composer-options: --ignore-platform-reqs

- name: Run the unit tests (non-risky)
- name: Run the unit tests without caching (non-risky)
if: matrix.risky == false
run: vendor/bin/phpunit --no-coverage
env:
PHPCS_VERSION: ${{ matrix.phpcs_version == '4.0.x-dev' && '4.0.0' || matrix.phpcs_version }}
PHPCSUTILS_USE_CACHE: false

- name: Run the unit tests with caching (non-risky)
if: matrix.risky == false
run: vendor/bin/phpunit --testsuite PHPCSUtils --no-coverage --repeat 2
env:
PHPCS_VERSION: ${{ matrix.phpcs_version == '4.0.x-dev' && '4.0.0' || matrix.phpcs_version }}
PHPCSUTILS_USE_CACHE: true

- name: Run the unit tests (risky)
if: ${{ matrix.risky }}
Expand Down Expand Up @@ -281,17 +289,19 @@ jobs:
if: ${{ steps.phpunit_version.outputs.VERSION >= '9.3' }}
run: vendor/bin/phpunit --coverage-cache ./build/phpunit-cache --warm-coverage-cache

- name: "Run the unit tests with code coverage (PHPUnit < 9.3)"
- name: "Run the unit tests with caching with code coverage (PHPUnit < 9.3)"
if: ${{ steps.phpunit_version.outputs.VERSION < '9.3' }}
run: vendor/bin/phpunit
env:
PHPCS_VERSION: ${{ matrix.phpcs_version }}
PHPCSUTILS_USE_CACHE: true

- name: "Run the unit tests with code coverage (PHPUnit 9.3+)"
- name: "Run the unit tests with caching with code coverage (PHPUnit 9.3+)"
if: ${{ steps.phpunit_version.outputs.VERSION >= '9.3' }}
run: vendor/bin/phpunit --coverage-cache ./build/phpunit-cache
env:
PHPCS_VERSION: ${{ matrix.phpcs_version }}
PHPCSUTILS_USE_CACHE: true

# Uploading the results with PHP Coveralls v1 won't work from GH Actions, so switch the PHP version.
- name: Switch to PHP 7.4
Expand Down
203 changes: 203 additions & 0 deletions PHPCSUtils/Internal/Cache.php
@@ -0,0 +1,203 @@
<?php
/**
* PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.
*
* @package PHPCSUtils
* @copyright 2019-2020 PHPCSUtils Contributors
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
* @link https://github.com/PHPCSStandards/PHPCSUtils
*/

namespace PHPCSUtils\Internal;

use PHP_CodeSniffer\Files\File;

/**
* Results cache.
*
* Allows to cache the return value of utility functions which do a lot of token walking.
* Those type of utilities can significantly slow down file scanning, especially
* with large files and when multiple sniffs use the same utility function.
*
* Caching the results can significantly speed things up, though it can also eat memory,
* so use with care.
*
* Typical usage:
* ```php
* function doSomething()
* {
* if (Cache::isCached($phpcsFile, __METHOD__, $stackPtr) === true) {
* return Cache::get($phpcsFile, __METHOD__, $stackPtr);
* }
*
* // Do something.
*
* Cache::set($phpcsFile, __METHOD__, $stackPtr, $returnValue);
* return $returnValue;
* }
* ```
*
* ---------------------------------------------------------------------------------------------
* This class is only intended for internal use by PHPCSUtils and is not part of the public API.
* This also means that it has no promise of backward compatibility.
* ---------------------------------------------------------------------------------------------
*
* @internal
*
* @since 1.0.0
*/
final class Cache
{

/**
* Whether caching is enabled or not.
*
* Note: this switch is ONLY intended for use within test suites and should never
* be touched in any other circumstances!
*
* Don't forget to always turn the cache back on in a `tear_down()` method!
*
* @var bool
*/
public static $enabled = true;

/**
* Results cache.
*
* @var array<int, array<string, array>> Format: $cache[$loop][$fileName][$key][$id] = mixed $value;
*/
private static $cache = [];

/**
* Check whether a result has been cached for a certain utility function.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param string $key The key to identify a particular set of results.
* It is recommended to pass __METHOD__ to this parameter.
* @param int|string $id Unique identifier for these results.
* Generally speaking this will be the $stackPtr passed
* to the utility function, but it can also something else,
* like a serialization of args passed to a function or an
* md5 hash of an input.
*
* @return bool
*/
public static function isCached(File $phpcsFile, $key, $id)
{
if (self::$enabled === false) {
return false;
}

$fileName = $phpcsFile->getFilename();
$loop = $phpcsFile->fixer->enabled === true ? $phpcsFile->fixer->loops : 0;

return isset(self::$cache[$loop][$fileName][$key])
&& \array_key_exists($id, self::$cache[$loop][$fileName][$key]);
}

/**
* Retrieve a previously cached result for a certain utility function.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param string $key The key to identify a particular set of results.
* It is recommended to pass __METHOD__ to this parameter.
* @param int|string $id Unique identifier for these results.
* Generally speaking this will be the $stackPtr passed
* to the utility function, but it can also something else,
* like a serialization of args passed to a function or an
* md5 hash of an input.
*
* @return mixed
*/
public static function get(File $phpcsFile, $key, $id)
{
if (self::$enabled === false) {
return null;
}

$fileName = $phpcsFile->getFilename();
$loop = $phpcsFile->fixer->enabled === true ? $phpcsFile->fixer->loops : 0;

if (isset(self::$cache[$loop][$fileName][$key])
&& \array_key_exists($id, self::$cache[$loop][$fileName][$key])
) {
return self::$cache[$loop][$fileName][$key][$id];
}

return null;
}

/**
* Retrieve all previously cached results for a certain utility function and a certain file.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param string $key The key to identify a particular set of results.
* It is recommended to pass __METHOD__ to this parameter.
*
* @return array
*/
public static function getForFile(File $phpcsFile, $key)
{
if (self::$enabled === false) {
return [];
}

$fileName = $phpcsFile->getFilename();
$loop = $phpcsFile->fixer->enabled === true ? $phpcsFile->fixer->loops : 0;

if (isset(self::$cache[$loop][$fileName])
&& \array_key_exists($key, self::$cache[$loop][$fileName])
) {
return self::$cache[$loop][$fileName][$key];
}

return [];
}

/**
* Cache the result for a certain utility function.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param string $key The key to identify a particular set of results.
* It is recommended to pass __METHOD__ to this parameter.
* @param int|string $id Unique identifier for these results.
* Generally speaking this will be the $stackPtr passed
* to the utility function, but it can also something else,
* like a serialization of args passed to a function or an
* md5 hash of an input.
* @param mixed $value An arbitrary value to write to the cache.
*
* @return mixed
*/
public static function set(File $phpcsFile, $key, $id, $value)
{
if (self::$enabled === false) {
return;
}

$fileName = $phpcsFile->getFilename();
$loop = $phpcsFile->fixer->enabled === true ? $phpcsFile->fixer->loops : 0;

/*
* If this is a phpcbf run and we've reached the next loop, clear the cache
* of all previous loops to free up memory.
*/
if (isset(self::$cache[$loop]) === false
&& empty(self::$cache) === false
) {
self::clear();
}

self::$cache[$loop][$fileName][$key][$id] = $value;
}

/**
* Clear the cache.
*
* @return void
*/
public static function clear()
{
self::$cache = [];
}
}

0 comments on commit 756d8fc

Please sign in to comment.