PSR-4:Autoloader(composer)和扩展名称空间,确保可回退php
我的命名空间回退和在Composer中使用PSR-4加载程序时遇到问题 我想做的是:PSR-4:Autoloader(composer)和扩展名称空间,确保可回退php,php,namespaces,composer-php,psr-4,Php,Namespaces,Composer Php,Psr 4,我的命名空间回退和在Composer中使用PSR-4加载程序时遇到问题 我想做的是: 具有可覆盖/扩展的核心 核心基于接口 目录结构如下所示: site/app/View/Example.php site/src/ACME/app/View/Example.php site/src/ACME/app/Interface/View.php namespace ACME\App\Site\View; class ViewExample extends View { 我没有设置此配置,因此如果您
site/app/View/Example.php
site/src/ACME/app/View/Example.php
site/src/ACME/app/Interface/View.php
namespace ACME\App\Site\View;
class ViewExample extends View {
我没有设置此配置,因此如果您有更好的建议,请尝试
我的composer json与psr-4类似:
"autoload": {
"psr-4": {
"ACME\\App\\Site\\" : "app/",
"ACME\\App\\" : "src/AMCE/app/"
}
}
我认为这会使ACME\App\Site\View在没有找到站点的情况下返回到ACME\App\View(注意,我还没有完成接口部分…)
我的site/app/View/Example.php代码如下:
site/app/View/Example.php
site/src/ACME/app/View/Example.php
site/src/ACME/app/Interface/View.php
namespace ACME\App\Site\View;
class ViewExample extends View {
当我有site/app/View/View.php时,它也可以工作。这看起来像:
namespace ACME\App\Site\View;
class View extends \ACME\App\View\View {
站点/src/app/View/View.php如下所示:
namespace ACME\APP\View;
class View {
这个应该使用接口(我还没试过)
所以我真正想做的是使它不必有site/app/View/View.php,也不必有site/app/View/Example.php——它可以使用site/src/ACME/app/View/Example.php
对不起,我是新来的名称空间,所以我可能不是很好的措辞
我的意思是,我认为ACME\App\Site会退回到ACME\App,但事实并非如此?还是我做错了?目前,它需要所有文件到位。编辑:原来我错了,可以让您的示例使用PSR-4!您只需要为可以从不同位置加载的名称空间指定一个目录数组
简易解决方案
{
"autoload": {
"psr-4": {
"ACME\\App\\Site\\": ["app/", "src/ACME/app"],
"ACME\\App\\": "src/ACME/app/"
}
}
}
就我个人而言,我宁愿更明确地命名我的名称空间,见下文
原始答案
当尝试加载不存在的文件时,composer PSR-4加载程序不会后退。它只是立即失效。其流程如下所示:
namespace ACME\App\Site\View;
class View extends \ACME\App\View\View {
\ACME\App\Site\View
\ACME\App\Site
(您的第一个PSR-4条目)匹配app/View.php
ACME\Site
名称空间保存可重用代码,并使用ACME\MySiteName
保存特定于站点的代码。这样就不会有歧义,而且composer在加载您的类时也不会有问题
但我不想重新安排我的名称空间强>
好的,那很好,但是你必须用黑客来解决你的问题。Composer有一个classmap
加载程序,您必须使用它而不是首选的PSR-4加载程序
{
"autoload": {
"classmap": ["app/", "src/"]
}
}
名称空间和自动加载不是此作业的正确工具。名称空间只是确保两个人(或部分代码)不使用相同的名称来表示不同的内容的一种方法。自动加载只是一种避免列出要从中加载代码的每个源文件的方法 当您在另一个类中重写一个类的行为时,这些类不是同一个类;通常,您希望继承默认操作并重用其中的一部分 您可能希望为不同的目的创建几个子类,因此需要有一个存放要使用的逻辑的地方。处理此问题的组件称为“服务定位器”,有时称为“DI容器”
名称空间允许您将短名称映射到更长、唯一的类名;自动加载允许您将特定的唯一类名映射到源文件;服务位置是您在特定情况下选择要使用的唯一类的方式。让我们稍微分离一下,因为它们现在都混在一起了 我想做的是:
class \ACME\App\Site\View\ViewExample extends \ACME\App\Site\View\View {}
class \ACME\App\Site\View\View extends \ACME\App\View\View {}
class \ACME\App\View\View {}
您有三个显式命名的类。您需要三个与名称空间和类名匹配的文件。自动加载不需要检测是否存在类,因为您不能选择从不存在的类继承,或者忽略它
另一方面,在默认情况下实现三个级别的继承很可能太多了。在我看来,这是一个糟糕的设计,会使维护代码变得比必要的更困难。根据你想要实现的目标,有很多选择可以让你更容易地实现你想要的。例如,要更改行为的某些细节,可以使用decorator模式或strategy模式
所以我真正想做的是使它不必有site/app/View/View.php,也不必有site/app/View/Example.php——它可以使用site/src/ACME/app/View/Example.php
你不能有这个。您的代码明确声明它继承自\ACME\App\Site\View\View
,因此该类必须存在于某个地方
这与任何自动加载无关。为了进行实验,您可以将所有代码添加到一个文件中,然后运行它。这将使PHP立即了解所有类,问题将变得显而易见:当其他类继承某个类时,您无法删除该类
对不起,我是新来的名称空间,所以我可能不是很好的措辞
名称空间没有什么特别之处,如果使用带有下划线的PSR-0样式的类名,也会出现同样的问题:
class ACME_App_Site_View_ViewExample extends ACME_App_Site_View_View {}
// This class MUST be present for the above class to work
class ACME_App_Site_View_View extends ACME_App_View_View {}
class ACME_App_View_View {}
名称空间的主要新特性是可以在seco下导入一个类