Ответ 1
Я думаю, вы довольно многое поняли. Хотя, я думаю, вам нужен авторитетный ответ.
Верно, что в документации не упоминается "rw+"
. Тем не менее, есть что-то лучше: исходный код PHP!
Отверстие кролика
Мне было трудно ориентироваться в исходном коде до тех пор, пока я не нашел статью с исходным кодом PHP для разработчиков PHP (часть 1, часть 2, часть 3, Часть 4). Я знаю, что ссылки перепрыгивают между двумя сайтами, эта серия такова. Кстати, я не нашел объявленную часть 5.
Примечание. Эти статьи старые, они говорят о PHP 5.4.
Посмотрим, что на самом деле делает fopen
... давайте попадаем в кроличью нору...
Сначала мы рассмотрим определение функции (которое я нашел по рекомендации связанной части 2 выше). Я заметил, что он использует php_stream_open_wrapper_ex
, который я найден в другом месте, он просто использует _php_stream_open_wrapper_ex
, который мы находим в stream.c.
Что делает _php_stream_open_wrapper_ex
с mode
? Он передает его stream_opener
.
Поиск определения stream_opener
привел меня к типу php_stream_wrapper_ops
в php_streams.h.
Поиск использования типа php_stream_wrapper_ops
привел меня к plain_wrapper.c.
На самом деле существует много инициализаций php_stream_wrapper_ops
, которые позволяют открывать разные вещи. Мы смотрим на php_fopen_wrapper.c, поскольку он имеет инициализацию php_stream_wrapper_ops
, где stream_opener
есть php_plain_files_stream_opener
.
Мы добираемся туда...
php_plain_files_stream_opener
далее в том же файле. Он делегирует php_stream_fopen_rel
.
php_streams.h
определяет php_stream_fopen_rel
с помощью _php_stream_fopen
. Что называется назад на plain_wrapper.c.
Наконец, _php_stream_fopen
вызывает php_stream_parse_fopen_modes
. Который возьмет строку и выведет некоторые флаги, Yay!
Wonderland
Давайте посмотрим на php_stream_parse_fopen_modes
:
PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags)
{
int flags;
switch (mode[0]) {
case 'r':
flags = 0;
break;
case 'w':
flags = O_TRUNC|O_CREAT;
break;
case 'a':
flags = O_CREAT|O_APPEND;
break;
case 'x':
flags = O_CREAT|O_EXCL;
break;
case 'c':
flags = O_CREAT;
break;
default:
/* unknown mode */
return FAILURE;
}
if (strchr(mode, '+')) {
flags |= O_RDWR;
} else if (flags) {
flags |= O_WRONLY;
} else {
flags |= O_RDONLY;
}
#if defined(O_CLOEXEC)
if (strchr(mode, 'e')) {
flags |= O_CLOEXEC;
}
#endif
#if defined(O_NONBLOCK)
if (strchr(mode, 'n')) {
flags |= O_NONBLOCK;
}
#endif
#if defined(_O_TEXT) && defined(O_BINARY)
if (strchr(mode, 't')) {
flags |= _O_TEXT;
} else {
flags |= O_BINARY;
}
#endif
*open_flags = flags;
return SUCCESS;
}
Для абстрактного, это то, что он делает (игнорируя детали):
-
Он принимает первый символ
mode
и проверяет, есть ли онr
,w
,a
,x
,c
. Если он распознает любой из них, он устанавливает соответствующий флаг. В противном случае мы имеемFAILURE
. -
Он ищет
+
где-то в строке и устанавливает соответствующие флаги. -
Он ищет
e
,n
иt
(в зависимости от директив препроцессора) где-то в строке и устанавливает соответствующие флаги. -
Возврат
SUCCESS
.
Возвращение в реальный мир
Вы спросили:
В чем разница между режимами fopen "r +" и "rw +" в PHP?
Ничего. PHP заботится только о том, что строка начинается с "r"
и имеет "+"
. "w"
игнорируется.
Заключительная записка. Хотя заманчиво играть с ней и писать такие вещи, как "read+"
, будьте осторожны с этим, потому что эта буква может когда-нибудь иметь какое-то значение. Он не был бы совместимым с переходом. Фактически, в некотором контексте "e"
уже имеет смысл. Вместо этого я предлагаю, придерживаясь документации.
Спасибо за оправдание, чтобы посмотреть исходный код PHP.