При вызове file_put_contents()
внутри деструктора он заставляет файлы записываться в SERVER_ROOT
… (Yikes!) Обходные решения?
tldr:
Я хочу кэшировать массив, возможно, содержащий сериализованные экземпляры класса. Я решил, что на данный момент я бы написал класс, который реализует кеш, используя unserialize()/file_get_contents()
и serialize()/file_put_contents()
а затем скрывает его функциональность за более общим классом Cache. (Я не знаю, будет ли хост моего клиента иметь общую память или PEAR и т. Д.)
<?php class CacheFile { private $filename; private $data; private $dirty = false; function __construct($filename) { $this->filename = $filename; $this->load(); } function __destruct() { // Calling file_put_contents within a destructor causes files to be written in SERVER_ROOT... $this->flush(); } private function load() { if(!file_exists($this->filename)) { $this->data = array(); } else { $this->data = unserialize(file_get_contents($this->filename)); // todo } $this->dirty = false; } private function persist() { file_put_contents($this->filename, serialize($this->data)); $this->dirty = false; } public function get($key) { if(array_key_exists($key, $this->data)) { return $this->data[$key]; } else { return false; } } public function set($key, $value) { if(!array_key_exists($key, $this->data)) { $dirty = true; } else if($this->data[$key] !== $value) { $dirty = true; } if($dirty) { $this->dirty = true; $this->data[$key] = $value; } } public function flush() { if($this->dirty) { $this->persist(); } } } $cache = new CacheFile("cache"); var_dump( $cache->get("item") ); $cache->set("item", 42); //$cache->flush(); var_dump( $cache->get("item") ); ?>
См. Вызов flush()
в деструкторе? Я действительно не хочу иметь функцию public flush()
потому что она специфична для реализации.
Я предполагаю, что вы не указали полный путь в $this->filename
.
В некоторых конфигурациях PHP, когда вызываются деструкторы (в фазе завершения сценариев), рабочий каталог может меняться. Затем относительные пути разрешаются в другое место.
Сравните с соответствующим примечанием в Руководстве по PHP :
Заметка:
Деструкторы, вызываемые во время выключения сценария, уже отправлены HTTP-заголовками. Рабочий каталог на фазе завершения сценария может отличаться от некоторых SAPI (например, Apache).
Если вы сделаете этот путь абсолютным, он будет работать, как ожидалось.
Изменить. Поскольку вы обновляете свой код, это простой способ убедиться, что у вас есть абсолютный путь:
$cache = new CacheFile(realpath("cache"));
Или намного лучше внутри конструктора:
$this->filename = realpath($filename);
Вы можете создать дескриптор файла в load()
который вы можете использовать в __destruct()
или flush()
.
Вы используете относительный путь как $ filename? Я бы прошел в абсолютном пути туда, где вы хотите файл. Если вы хотите, чтобы это было относительно вашего сценария, вы могли бы использовать что-то вроде:
$filename = dirname($_SERVER['SCRIPT_FILENAME']) . PATH_SEPARATOR . $filename;