[英]PHP - PSR-4: Autoloader (composer) and multiple namespaces with the same root
[英]PSR-4: Autoloader (composer) and extending namespaces ensuring fallback php
我的命名空間回退和在Composer中使用PSR-4加載程序時遇到問題。
我想做的是這樣的:
目錄結構如下:
site/app/View/Example.php
site/src/ACME/app/View/Example.php
site/src/ACME/app/Interface/View.php
我沒有設置此配置,因此,如果您有更好的建議,請繼續使用。
我的作曲家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代碼如下所示:
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 {
site / 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-不是嗎? 還是我做錯了? 目前,它需要所有文件。
讓我們稍微分開一些東西,因為現在它們已經混合在一起了。
我想做的是這樣的:
- 有一個可以覆蓋/擴展的核心。
- 核心基於接口。
這聽起來像基本的面向對象的繼承。 接口定義了建議的公共行為,核心實現了所需的基礎,詳細實現更改了某些部分,並重用了其他部分。
讓我們以PHP用絕對名稱空間名稱看到它的方式來編寫示例代碼:
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 {}
您有三個明確命名的類。 您需要三個與名稱空間和類名稱匹配的文件。 自動加載不需要檢測是否存在類-因為您不能選擇從不存在的類繼承,否則就可以忽略它。
另一方面,默認情況下實現三個繼承級別的可能性很大。 對我來說,這看起來像是糟糕的設計,並且會使維護代碼變得不必要。 根據您要實現的目標,有很多替代方法可以使您更輕松地實現所需的目標。 例如,要更改某些行為細節,可以使用裝飾器模式或策略模式。
因此,我真正想做的是制作它,因此我不必擁有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 {}
命名空間的主要新功能是,您可以use OtherNamespace\\Classname
在文件中以第二個名稱導入一個類。 但這只是該文件范圍內的別名(即,它不影響其他文件或全局范圍)。
編輯:原來我原來錯了,有可能讓您的示例在PSR-4上工作! 您只需為可從不同位置加載的名稱空間指定目錄數組。
簡單的解決方案
{
"autoload": {
"psr-4": {
"ACME\\App\\Site\\": ["app/", "src/ACME/app"],
"ACME\\App\\": "src/ACME/app/"
}
}
}
就個人而言,我寧願更明確地命名我的命名空間,請參見下文。
原始答案
嘗試加載不存在的文件時,作曲家PSR-4加載器不會后退。 它只是立即失敗。 其流程如下所示:
\\ACME\\App\\Site\\View
未加載 \\ACME\\App\\Site
(您的第一個PSR-4條目)匹配。 app/View.php
它永遠不會返回到步驟3並嘗試下一個名稱空間。
那么我該如何解決呢?
看來您想將可重用的庫代碼與站點代碼分開。 如果是這樣,我將使用單獨的名稱空間。 例如,使用ACME\\Site
命名空間保存您的可重用代碼,並使用ACME\\MySiteName
作為站點特定的代碼。 這樣就不會有歧義,作曲家也不會在加載類時遇到麻煩。
但是我不想重新排列我的名稱空間!
好的,那很好,但是您必須使用黑客解決您的問題。 Composer有一個classmap
加載程序,您必須使用它而不是首選的PSR-4加載程序。
{
"autoload": {
"classmap": ["app/", "src/"]
}
}
命名空間和自動加載不是完成此任務的正確工具。 名稱空間只是一種確保兩個人(或代碼的一部分)不使用相同名稱來表示不同含義的一種方法。 自動加載只是避免列出要加載代碼的每個源文件的一種方法。
當您在另一個類中覆蓋一個類的行為時,它們就不是同一類;它們是同一類。 通常,您需要繼承默認操作並重用其中的一部分。
您可能需要創建多個子類以實現不同的用途,因此需要在某個地方保存要使用的邏輯。 處理該問題的組件稱為“服務定位器”,有時也稱為“ DI容器”。
命名空間使您可以將短名稱映射到更長的唯一類名稱。 自動加載讓您將特定的唯一類名稱映射到源文件; 服務位置是您在特定情況下選擇要使用的唯一類的方式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.