从几个 .php 文件中解包/合并 PHP 代码

Unwrap / amalgamate PHP code from several .php files

出于调试目的,在处理包含许多文件/许多 include 的 PHP 项目时(例如:Wordpress 代码),有时我会对查看“展开的”代码感兴趣,并且合并/展平(“展平”是类似 Photoshop 的工具中使用的术语,当您将多个图层合并为一个图层时)所有文件合并到一个大 PHP 文件中。

如何合并多个PHP文件?

示例:

$ php index.php --amalgamation

将这些文件作为输入:

并生成此合并输出:

<?php
$color = 'green';
$fruit = 'apple';
echo "A $color $fruit";
?>

(它应该也适用于许多文件,例如,如果 index.php 包含 vars.php,而 vars.php 本身包含 abc.php)。

我们可以编写一个 amalgamation/bundling 脚本来获取给定文件的内容并匹配 include|require 的任何实例,然后获取任何引用文件的内容,并替换 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 引用替换为实际代码。该函数还包括一个注释行,指示包含文件的源,这可能会派上用场if/when你正在调试编译的捆绑文件。

Notes/Homework:

  • 您可能需要完善基目录引用例程。 (预计依赖 PHP include_path 的“不完整”文件路径会遇到麻烦。)
  • 没有控制_once,代码会重新收录。 (通过记录包含的文件路径和跳过重复项很容易补救。)
  • 仅在 "path/file.php" 上进行匹配,即。 single/double 引号内的完整字符串。连接的字符串不匹配。
  • 不理解包含变量或常量的路径。必须对文件进行评估,没有副作用!,才能做到这一点。
  • 如果您使用 declare(strict_types=1);,请将其置于顶部并消除以下实例。
  • 此处未提及的文件捆绑可能会产生其他副作用。
  • 正则表达式没有 lookbehind/around 来查看您的 include/require 是否被注释掉了!
  • 如果您的代码跳进跳出 PHP 模式并脱口而出 HTML,所有赌注都将取消
  • 管理自动加载的内容 类 超出了此代码段的范围。

请报告任何故障和边缘情况。随意开发和(自由)分享。