Ответ 1
Поскольку этот ответ длинный, здесь резюме: Нет, file_get_contents()
не является атомарным, так как оно не соблюдает консультативные блокировки.
О блокировке файлов в PHP:
В PHP, хотя на платформе * nix блокировка файловой системы является только рекомендательной. Per документы (Emphasis mine):
PHP поддерживает переносимый способ блокировки полных файлов в виде сообщений (что означает, что все программы доступа должны использовать тот же способ блокировки или не работать). По умолчанию эта функция блокируется до тех пор, пока не будет получен требуемый замок; это можно контролировать (на платформах, отличных от Windows) с опцией LOCK_NB, описанной ниже.
Итак, если все процессы, которые обращаются к файлу, используют этот метод блокировки, вы в порядке.
Однако, если вы пишете статический HTML файл с разумным веб-сервером, блокировка будет проигнорирована. В середине записи, если запрос приходит, Apache будет обслуживать частично написанный файл. Блокировки не будут влиять на другой процесс, считывающий блокировку.
Единственное реальное исключение - если вы используете специальную опцию mount -o mand
в файловой системе, чтобы включить обязательную блокировку (но это не очень сильно используется и может иметь ограничение производительности).
Прочитайте File Locking для получения дополнительной информации. А именно раздел под Unix:
Это означает, что взаимодействующие процессы могут использовать блокировки для координации доступа к файлу между собой, но программы также могут игнорировать блокировки и получать доступ к файлу любым способом, который они выбирают.
Итак, в заключение, использование LOCK_EX
создаст консультативную блокировку файла. Любая попытка прочитать файл блокируется, только если читатель уважает и/или проверяет блокировку. Если они этого не сделают, блокировка будет проигнорирована (поскольку это может быть).
Попробуйте. В одном процессе:
file_put_contents('test.txt', 'Foo bar');
$f = fopen('test.txt', 'a+');
if (flock($f, LOCK_EX)) {
sleep(10);
fseek($f, 0);
var_dump(fgets($f, 4048));
flock($f, LOCK_UN);
}
fclose($f);
И пока он спит, назовите это:
$f = fopen('test.txt', 'a+');
fwrite($f, 'foobar');
fclose($f);
Выход будет foobar
...
О file_get_contents
в частности:
К вашему другому конкретному вопросу, во-первых, нет параметра LOCK_EX
для file_get_contents
. Поэтому вы не можете передать это.
Теперь, глядя на исходный код, мы можем увидеть функцию file_get_contents
, определенную в строке 521. Нет вызовов на внутренняя функция php_stream_lock
, как это бывает при передаче file_put_contents('file', 'txt', LOCK_EX);
, определенных в строке 589 того же файла.
Итак, давайте протестируем его, будем ли мы:
В файле file1.php:
file_put_contents('test.txt', 'Foo bar');
$f = fopen('test.txt', 'a+');
if (flock($f, LOCK_EX)) {
sleep(10);
fseek($f, 0);
var_dump(fgets($f, 4048));
flock($f, LOCK_UN);
}
fclose($f);
В файле2.php:
var_dump(file_get_contents('test.txt'));
При запуске file2.php
немедленно возвращается. Так что нет, не кажется, что file_get_contents
соблюдает блокировки файлов вообще...