在一个非常抽象的例子中:我想要在包A中加载一些模板或文件,这些模板或文件位于第三方包B中,它们都在Application Z中加载,例如:
{
"name": "application/Z",
"require": {
"lib/A": "*"
}
}
和
{
"name": "lib/A",
"require": {
"lib\B": "*"
}
}
现在我喜欢这样做:
<?php
namespace lib\A;
class TemplateLoader {
public function getInclude() {
return file_get_contents(__DIR__ . '/../../vendor/lib/b/templates/my.inc');
}
}
这样可行,但使用相对路径似乎是一个坏主意,尤其是在单元测试中,路径以'../vendor'
开头。所以路径不可靠。
现在我的问题:是否可以从自动加载器中使用的composer获取供应商路径?或者有这样的实现的最佳实践吗?
创建函数\Lib\B\Templates::getIncludePath()
的明显解决方案是不可能的,因为我无法访问此库。
答案 0 :(得分:1)
假设lib/B
的composer.json包含:
"autoload": {
"psr-0": {
"lib\\B": "src/"
}
},
要回答这个问题,您可以使用作曲家的ClassLoader,因此您的lib\A\TemplateLoader
可能如下所示:
namespace lib\A;
use Composer\Autoload\ClassLoader;
class TemplateLoader {
/** @var ClassLoader */
protected $loader;
public function __construct(ClassLoader $loader)
{
$this->loader = $loader;
}
public function getInclude() {
$libs = $this->loader->getPrefixes();
if (!isset($libs['lib\\B'])) {
throw new \RuntimeException("Package lib/B is not loaded. Be sure it is included in composer.json and you ran 'compose install'.");
}
$path = $libs['lib\\B'][0];
// At this point $path contains base path for classes in lib/B package,
// depending on 'autoload' directive of lib/B's composer.json above.
// In this example it is '/full/path/to/vendor/lib/B/src'
$parts = explode('/', $path);
array_pop($parts);
$path = implode('/', $parts);
return file_get_contents($path . '/templates/my.inc');
}
}
lib/B
并在那里添加模板加载器:namespace lib\B;
class TemplateLoader {
public static function getTemplate($name) {
return file_get_contents(__DIR__ . '/../templates/'.$name);
}
}
所以在lib\A
中它很简单:
namespace lib\A;
class TemplateLoader {
public function getInclude() {
return \lib\B\TemplateLoader::getTemplate('my.inc');
}
}
答案 1 :(得分:1)
至于寻找作曲家vendor-dir
的方法,我看到过一些尝试做这种非常脆弱的事情,我不建议。
一种非常糟糕的方法是通过查看autoload.php
的两个常见位置来对上下文进行假设。
稍微好一点的方法是对spl_autoload_functions
的结果使用反射来确定自动加载器来自的文件。
理想的方法是在项目中使用composer/composer
作为库,并在本地存储库中查找包元数据。
我建议,一种非常简单的方法是使用模板加载器配置路径。这可能允许您拥有多个第三方库,这些库具有不同的约定,它们放置在仓库中。