Странное поведение include

236
02 августа 2017, 22:39

Есть файл конфига, который возвращает массив значений. Содержимое:

<?php return (array ());

В классе работы с конфигами, подключаю этот файл и получаю его значение так:

$arr = include($full_path);

Потом стоит проверка if(!is_array($arr))... и в случае если это не массив - выбрасывается исключение.

Возникла странная проблема. На корректное содержимое конфига, однажды я получил исключение. Я проверил файл конфига, он в порядке.

Ошибка возникает тогда, когда выполняется сохранение конфига. Если очень быстро обновить страницу, в одной из итераций получится выбить ошибку. Без сохранения ошибка кажется не возникает.

Сохраняю конфиг функцией file_put_contents. Конечно я сразу же подумал что проблема в LOCK_EX, но это не так! Я убирал этот параметр, ошибка хоть и появлялась реже, она осталась и несколько раз мне удалось её отловить.

Если ДО строчки с проверкой if(!is_array($arr))... вставить var_dump(file_get_contents($full_path)), ошибку отловливать не получается (у меня не получилось во всяком случае, думаю файл ждет загрузки, а инклуд нет - это основная догадка). Сама же переменная $arr содержит 1, если её вызвать до выброса исключения, что говорит о том что файл "успешно" подключен.

Обратите внимание на то, что ошибка возникает после быстрого обновления страницы и не сразу. Я пробовал до инклуда вставлять условие с is_readable, оно вообще ни разу не выдало false.

Учтите, сохранение проходит без проблем. Учтите, ошибка проявляется не каждый раз, и не имеет четкого триггера для вызова, поймать её можно обновляя страницу много раз и быстро (ну или зажав f5), при этом время зажатия не определено.

Если кто-то знает в чем причина такого поведения, помогите найти решение.

Моя задача, избавиться от ошибки. Если это невозможно, то хотя бы найти способ выбрасывать конкретную ошибку вроде "файл сейчас недоступен для подключения"

Код класса и конфига

Answer 1

В php используется рекомендательная блокировка. Защита файла от конкурентного доступа работает только если все писатели и читатели ипользуют в доступе LOCK_(EX|SH). Те, кто не использует флаги LOCK_(EX|SH), будут бесконтрольно писать и читать в любой момент.

В php с этим плохо. file(), include, require и так далее - не используют блокировку, даже file_put_contents(LOCK_EX) есть, а file_get_contents (LOCK_SH) не существует.

Если не нужно редактировать файл, а полностью перезаписывать, и старое содержимое файла не влияет на новое, то можно писать во временный файл и потом делать rename этого файла в нужное имя. При записи во временный файл с рэндомным именем нет конкурентного доступа, а rename атомарен.

При таком подходе никто не должен писать в конечный файл напрямую.

Answer 2

Файл 1.

<?php
function getConfig($full_path) {
   return (array());
}

Файл 2.

<?php
include('файл1.php');
$arr = getConfig($full_path);
if(!is_array($arr))...
READ ALSO
Оптимальная выборка из бд

Оптимальная выборка из бд

Делаю выборку по городу, у города есть районы, у них комплексы, а у комплексов квартирыВ конечном итоге мне нужно получить квартиры для определенного...

285
Не работает bootstrap на nginx + php-fpm

Не работает bootstrap на nginx + php-fpm

Кладу в папку с сайтом все нужный файлы и indexphp в итоге рисует мне страничку, но без стилей

336
Эффективна ли функция sleep()?

Эффективна ли функция sleep()?

Добрый день, хотим запустить скрипт, который рандомом на протяжении всего дня будет запускать различные функции

254