簡體   English   中英

PSR-4:自動加載器(composer)和擴展名稱空間,確保后備php

[英]PSR-4: Autoloader (composer) and extending namespaces ensuring fallback php

我的命名空間回退和在Composer中使用PSR-4加載程序時遇到問題。

我想做的是這樣的:

  1. 有一個可以覆蓋/擴展的核心。
  2. 核心基於接口。

目錄結構如下:

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-不是嗎? 還是我做錯了? 目前,它需要所有文件。

讓我們稍微分開一些東西,因為現在它們已經混合在一起了。

我想做的是這樣的:

  1. 有一個可以覆蓋/擴展的核心。
  2. 核心基於接口。

這聽起來像基本的面向對象的繼承。 接口定義了建議的公共行為,核心實現了所需的基礎,詳細實現更改了某些部分,並重用了其他部分。

讓我們以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加載器不會后退。 它只是立即失敗。 其流程如下所示:

  1. \\ACME\\App\\Site\\View未加載
  2. 掃描PSR-4條目以查找匹配的名稱空間
  3. 類名稱與名稱空間\\ACME\\App\\Site (您的第一個PSR-4條目)匹配。
  4. 加載文件app/View.php
  5. 文件不存在。 錯誤。

它永遠不會返回到步驟3並嘗試下一個名稱空間。

那么我該如何解決呢?

看來您想將可重用的庫代碼與站點代碼分開。 如果是這樣,我將使用單獨的名稱空間。 例如,使用ACME\\Site命名空間保存您的可重用代碼,並使用ACME\\MySiteName作為站點特定的代碼。 這樣就不會有歧義,作曲家也不會在加載類時遇到麻煩。

但是我不想重新排列我的名稱空間!

好的,那很好,但是您必須使用黑客解決您的問題。 Composer有一個classmap加載程序,您必須使用它而不是首選的PSR-4加載程序。

{
    "autoload": {
        "classmap": ["app/", "src/"]
    }
}

命名空間和自動加載不是完成此任務的正確工具。 名稱空間只是一種確保兩個人(或代碼的一部分)不使用相同名稱來表示不同含義的一種方法。 自動加載只是避免列出要加載代碼的每個源文件的一種方法。

當您在另一個類中覆蓋一個類的行為時,它們就不是同一類;它們是同一類。 通常,您需要繼承默認操作並重用其中的一部分。

您可能需要創建多個子類以實現不同的用途,因此需要在某個地方保存要使用的邏輯。 處理該問題的組件稱為“服務定位器”,有時也稱為“ DI容器”。

命名空間使您可以將短名稱映射到更長的唯一類名稱。 自動加載讓您將特定的唯一類名稱映射到源文件; 服務位置是您在特定情況下選擇要使用的唯一類的方式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM