В качестве учебного упражнения я пытаюсь сохранить скомпилированное состояние файла PHP, чтобы выполнить его позднее, без необходимости повторного просмотра zend_compile_file
.
Первым делом я написал расширение, которое перехватывает zend_compile_file
. Если запрос сделан для некомпилированного файла (например, file.php), он zend_op_array
данные zend_op_array
в другой файл (например, compiled-file.php). Если запрос сделан для такого скомпилированного файла, он загружает данные в новый zend_op_array
и затем возвращает его.
Для простоты я проигнорировал все, что связано с классами и функциями, поэтому я не ожидаю, что мое расширение будет работать над сценарием, который содержит их. Но другие более простые сценарии должны работать, я думаю?
Ну, он работает на очень простых скриптах, но часто просто зависает и достигает максимального времени выполнения. Я обнаружил, что это всегда дает сбой на ложной условной ветки Например, этот скрипт будет работать:
<?php
$a = 10;
$b = 5;
if ($b < $a)
echo $a;
Пока этот просто виснет
<?php
$a = 10;
$b = 5;
if ($b > $a)
echo $a;
Мой вопрос: правильно ли я предположить, что для простых сценариев без функций или классов достаточно сделать zend_op_array
копию zend_op_array
и вернуть ее для репликации компиляции PHP? Если нет, какие еще шаги я должен предпринять, чтобы это заработало?
Вот соответствующие файлы моего расширения: opdumper.c oploader.c
РЕДАКТИРОВАТЬ: мне удалось "исправить" мою проблему, изменив этот код:
void dump_znode_op(FILE* fp, znode_op node, zend_uchar type)
{
fwrite(&type, sizeof(type), 1, fp);
switch(type) {
case IS_UNDEF:
case IS_UNUSED:
break;
...
}
}
к этому:
void dump_znode_op(FILE* fp, znode_op node, zend_uchar type)
{
fwrite(&type, sizeof(type), 1, fp);
switch(type) {
case IS_UNDEF:
case IS_UNUSED:
fwrite(&(node.var), sizeof(node.var), 1, fp);
break;
...
}
}
(И, конечно, применяя подобное исправление к oploader.c)
Теперь я еще больше запутался... почему znode_op с типом IS_UNUSED
заботится о его значении!??