如何管理依赖项自动加载

Nik*_*kiC 4 php autoload

构建库时,我总是提供一个Autoloader处理库自动加载的类.自动加载器的注册方式如下:

require_once 'path/to/PHP-Parser/lib/PHPParser/Autoloader.php';
PHPParser_Autoloader::register();
Run Code Online (Sandbox Code Playgroud)

如果我的库依赖于另一个库,我不确定如何处理它.想象一下,PHPParser取决于a PHPLexer.现在使用库时需要编写:

require_once 'path/to/PHP-Lexer/lib/PHPLexer/Autoloader.php';
PHPLexer_Autoloader::register();

require_once 'path/to/PHP-Parser/lib/PHPParser/Autoloader.php';
PHPParser_Autoloader::register();
Run Code Online (Sandbox Code Playgroud)

如果不仅仅有一个依赖项或依赖项本身具有依赖项,这可能会很快变得混乱.

那么如何处理依赖自动加载呢?

我的一个想法是,库也应该为它的依赖关系处理自动加载,但这感觉不对.另一个想法是根本不提供自动加载器并假设人们使用UniversalClassLoader.虽然这似乎也不正确.

irc*_*ell 8

嗯,有几种方法可以解决这个问题,每种方法各有利弊:

  1. 对所有库使用通用的PSR-0自动加载器,并在初始化时注册其他项目的位置.

    • 好处:
      1. 实现起来非常简单
      2. 使用相同的代码,因此只能使用一个自动加载器
      3. 您可以在应用程序引导程序文件中注册所有路径,以便在一个位置定义所有库自动加载
    • 缺点
      1. 需要所有库实现PSR-0兼容的文件结构
      2. 由于应用程序引导程序需要引导应用程序内的所有内容(包括每个单独的库),因此会略微泄漏抽象级别.
      3. 将库的文件结构紧密地耦合到自动加载器(如果库实现了一个冲突的新文件,即使它们的工作文件也会破坏自动加载器)
  2. 为每个库定义自定义自动加载器.

    • 好处
      1. 实现起来非常简单.
      2. 保留库中的库自动加载语义.
      3. 由于责任分离,可维护的代码更好
    • 缺点
      1. 你的bootstrap文件中有很多硬编码的类(虽然不是很重要)
      2. 自动加载类的性能必须经过多个自动加载器
      3. 泄漏抽象级别,因为库可能需要更多的努力来引导而不仅仅是自动加载
  3. 为每个库实现bootstrap.php(最好由库提供)

    • 好处
      1. 实现起来非常简单.
      2. 保留库中的库自动加载语义
      3. 由于关注点分离,代码更好
      4. 能够定义非平凡的库引导代码而不会混淆应用程序的其他部分
    • 缺点
      1. 仍需要require_once '/path/to/lib/dir/bootstrap.php';初始化
      2. 性能(与第二种解决方案相同的原因)
      3. 大多数3pd库不实现引导文件,因此您可能必须维护一个.

就个人而言,我使用第三种选择.一个例子是我的CryptLib库中的bootstrap.php文件.要初始化它,只需调用bootstrap.您也可以使用任何PSR-0自动加载器,只是不要调用bootstrap.php,它会正常工作.但是使用bootstrap选项,如果我添加了在启动时注册自身的功能,我可以将它添加到bootstrap.php文件中并自动执行(而不是告诉用户他们需要执行"x,y" ,z"在启动时)......

关于你提到的通用类加载器选项(spl_autoload_register()不带参数调用),我个人不喜欢这个选项.首先,它降低了类名(它违反了PSR-0,我不喜欢它.我已经习惯了区分大小写的类 - >路径映射,现在实际上更喜欢它).其次,它总是使用相对路径,因此它将击败大多数操作码缓存.还有其他问题,但那些是大问题......