1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-14 10:17:33 +01:00
psalm/src/Psalm/Internal/Provider/ClassLikeStorageCacheProvider.php

157 lines
4.8 KiB
PHP
Raw Normal View History

2018-02-19 06:27:39 +01:00
<?php
2018-11-06 03:57:36 +01:00
namespace Psalm\Internal\Provider;
2018-02-19 06:27:39 +01:00
use Psalm\Config;
use Psalm\Storage\ClassLikeStorage;
class ClassLikeStorageCacheProvider
{
/**
* @var Config
*/
private $config;
/**
* @var string
*/
private $modified_timestamps = '';
const CLASS_CACHE_DIRECTORY = 'class_cache';
public function __construct(Config $config)
{
$this->config = $config;
2018-11-06 03:57:36 +01:00
$storage_dir = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'Storage' . DIRECTORY_SEPARATOR;
2018-02-19 06:27:39 +01:00
$dependent_files = [
$storage_dir . 'FileStorage.php',
2018-02-19 06:27:39 +01:00
$storage_dir . 'FunctionLikeStorage.php',
$storage_dir . 'ClassLikeStorage.php',
2018-02-19 06:27:39 +01:00
$storage_dir . 'MethodStorage.php',
];
if ($config->after_visit_classlikes) {
$dependent_files = array_merge($dependent_files, $config->plugin_paths);
}
2018-02-19 06:27:39 +01:00
foreach ($dependent_files as $dependent_file_path) {
if (!file_exists($dependent_file_path)) {
throw new \UnexpectedValueException($dependent_file_path . ' must exist');
}
$this->modified_timestamps .= ' ' . filemtime($dependent_file_path);
}
$this->modified_timestamps .= PSALM_VERSION . $this->config->hash;
2018-02-19 06:27:39 +01:00
}
/**
* @param string|null $file_path
* @param string|null $file_contents
*
* @return void
*/
public function writeToCache(ClassLikeStorage $storage, $file_path, $file_contents)
{
$fq_classlike_name_lc = strtolower($storage->name);
$cache_location = $this->getCacheLocationForClass($fq_classlike_name_lc, $file_path, true);
2018-02-19 06:27:39 +01:00
$storage->hash = $this->getCacheHash($file_path, $file_contents);
if ($this->config->use_igbinary) {
file_put_contents($cache_location, igbinary_serialize($storage));
} else {
file_put_contents($cache_location, serialize($storage));
}
2018-02-19 06:27:39 +01:00
}
/**
* @param string $fq_classlike_name_lc
* @param string|null $file_path
* @param string|null $file_contents
*
* @return ClassLikeStorage
*/
public function getLatestFromCache($fq_classlike_name_lc, $file_path, $file_contents)
{
$cached_value = $this->loadFromCache($fq_classlike_name_lc, $file_path);
2018-02-19 06:27:39 +01:00
if (!$cached_value) {
throw new \UnexpectedValueException($fq_classlike_name_lc . ' should be in cache');
2018-02-19 06:27:39 +01:00
}
$cache_hash = $this->getCacheHash($file_path, $file_contents);
2018-09-04 20:37:33 +02:00
/** @psalm-suppress TypeDoesNotContainType */
if (@get_class($cached_value) === '__PHP_Incomplete_Class'
|| $cache_hash !== $cached_value->hash
) {
unlink($this->getCacheLocationForClass($fq_classlike_name_lc, $file_path));
2018-02-19 06:27:39 +01:00
throw new \UnexpectedValueException($fq_classlike_name_lc . ' should not be outdated');
2018-02-19 06:27:39 +01:00
}
return $cached_value;
}
/**
* @param string|null $file_path
* @param string|null $file_contents
*
* @return string
*/
private function getCacheHash($file_path, $file_contents)
{
return sha1(($file_path ? $file_contents : '') . $this->modified_timestamps);
2018-02-19 06:27:39 +01:00
}
/**
* @param string $fq_classlike_name_lc
* @param string|null $file_path
2018-02-19 06:27:39 +01:00
*
* @return ClassLikeStorage|null
*/
private function loadFromCache($fq_classlike_name_lc, $file_path)
2018-02-19 06:27:39 +01:00
{
$cache_location = $this->getCacheLocationForClass($fq_classlike_name_lc, $file_path);
2018-02-19 06:27:39 +01:00
if (file_exists($cache_location)) {
if ($this->config->use_igbinary) {
/** @var ClassLikeStorage */
return igbinary_unserialize((string)file_get_contents($cache_location)) ?: null;
}
/** @var ClassLikeStorage */
return unserialize((string)file_get_contents($cache_location)) ?: null;
2018-02-19 06:27:39 +01:00
}
return null;
}
/**
* @param string $fq_classlike_name_lc
* @param string|null $file_path
2018-02-19 06:27:39 +01:00
* @param bool $create_directory
*
* @return string
*/
private function getCacheLocationForClass($fq_classlike_name_lc, $file_path, $create_directory = false)
2018-02-19 06:27:39 +01:00
{
$root_cache_directory = $this->config->getCacheDirectory();
if (!$root_cache_directory) {
throw new \UnexpectedValueException('No cache directory defined');
}
$parser_cache_directory = $root_cache_directory . DIRECTORY_SEPARATOR . self::CLASS_CACHE_DIRECTORY;
if ($create_directory && !is_dir($parser_cache_directory)) {
mkdir($parser_cache_directory, 0777, true);
}
return $parser_cache_directory
. DIRECTORY_SEPARATOR
. sha1(($file_path ? strtolower($file_path) . ' ' : '') . $fq_classlike_name_lc)
. ($this->config->use_igbinary ? '-igbinary' : '');
2018-02-19 06:27:39 +01:00
}
}