Развернуть/объединить 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, все ставки сняты.
  • Управление включением автоматически загружаемых классов выходит за рамки этого фрагмента.

Пожалуйста, сообщайте о любых глюках и крайних случаях. Не стесняйтесь разрабатывать и (свободно) делиться.

Другие вопросы по тегам