Развернуть/объединить PHP-код из нескольких файлов .php
В целях отладки при работе над проектами PHP со многими файлами/многими
include
(пример: код Wordpress), мне иногда было бы интересно увидеть «развернутый» код и объединить / сгладить («свести» — это терминология, используемая в инструментах, подобных Photoshop, когда вы объединяете много слоев в один слой) все файлы в один большой файл PHP.
Как сделать объединение нескольких файлов PHP?
Пример:
$ php index.php --amalgamation
будет принимать эти файлы в качестве входных данных:
vars.php
<?php $color = 'green'; $fruit = 'apple'; ?>
index.php
<?php include 'vars.php'; echo "A $color $fruit"; ?>
и создайте этот объединенный вывод:
<?php
$color = 'green';
$fruit = 'apple';
echo "A $color $fruit";
?>
(он должен работать также со многими файлами, например, если
index.php
включает
vars.php
который сам включает
abc.php
).
1 ответ
Мы можем написать сценарий объединения/объединения, который извлекает содержимое заданного файла и сопоставляет любые экземпляры
include|require
, а затем извлекает содержимое всех упомянутых файлов и заменяет вызовы include/require фактическим кодом.
Ниже приведена элементарная реализация, которая будет работать (на основе очень ограниченного теста файлов с вложенными ссылками) с любым количеством файлов, которые включают/требуют другие файлы.
<?php
// Main file that references further files:
$start = 'test/test.php';
function bundle_files(string $filepath)
{
// Fetch current code
$code = file_get_contents($filepath);
// Set directory for referred files
$dirname = pathinfo($filepath, PATHINFO_DIRNAME);
// Match and substitute include/require(_once) with code:
$rx = '~((include|require)(_once)?)\s+[\'"](?<path>[^\'"]+)[\'"];~';
$code = preg_replace_callback($rx, function($m) use ($dirname) {
// Ensure a valid filepath or abort:
if($path = realpath($dirname . '/' . $m['path'])) {
return bundle_files($path);
} else {
die("Filepath Read Fail: {$dirname}/{$m['path']}");
}
}, $code);
// Remove opening PHP tags, note source filepath
$code = preg_replace('~^\s*<\?php\s*~i', "\n// ==== Source: {$filepath} ====\n\n", $code);
// Remove closing PHP tags, if any
$code = preg_replace('~\?>\s*$~', '', $code);
return $code;
}
$bundle = '<?php ' . "\n" . bundle_files($start);
file_put_contents('bundle.php', $bundle);
echo $bundle;
Здесь мы используемpreg_replace_callback()
для сопоставления и замены в порядке появления, при этом обратный вызов вызывает функцию связывания для каждого совпадающего пути к файлу и заменяет ссылки include/require фактическим кодом. Функция также включает строку комментария, указывающую источник включаемого файла, который может пригодиться, если/когда вы отлаживаете скомпилированный пакетный файл.
Примечания/домашнее задание:
- Возможно, вам потребуется уточнить процедуру обращения к базовому каталогу. (Ожидайте проблем с «неполными» путями к файлам, которые зависят от PHP include_path.)
- Нет контроля над
_once
, код будет повторно включен. (Легко исправить, записав включенные пути к файлам и пропустив повторения.) - Сопоставление производится только на
"path/file.php"
, т.е. неразрывные строки внутри одинарных/двойных кавычек. Объединенные строки не совпадают. - Пути, включающие переменные или константы, не понимаются. Файлы должны быть оценены без побочных эффектов!, чтобы это было возможно.
- Если вы используете
declare(strict_types=1);
, поместите его поверх и устраните следующие экземпляры. - Могут быть другие побочные эффекты от объединения файлов, которые здесь не рассматриваются.
- Регулярное выражение не смотрит назад/вокруг, чтобы увидеть, закомментировано ли ваше включение/требование!
- Если ваш код переходит в режим PHP и выходит из него и выдает HTML, все ставки сняты.
- Управление включением автоматически загружаемых классов выходит за рамки этого фрагмента.
Пожалуйста, сообщайте о любых глюках и крайних случаях. Не стесняйтесь разрабатывать и (свободно) делиться.