CodeIgniter4 服務(wù)

2020-08-13 11:37 更新

引言

在CodeIgniter內(nèi)部的所有類實(shí)際上都是以”服務(wù)”的形式呈現(xiàn)的。這意味著,所有的類都是以定義在一個簡單的配置文件里,而非硬編碼所需要加載的類名,來進(jìn)行加載的。 該配置文件實(shí)際上扮演了一種為所需類創(chuàng)建新的實(shí)例的工廠的角色。

一個簡單的例子可能會講得更清楚,比如請?jiān)O(shè)想你需要獲得一個 Timer (計時器)類的實(shí)例,最簡單的方法就是為該類創(chuàng)建一個新的實(shí)例:

$timer = new \CodeIgniter\Debug\Timer();

這種方式運(yùn)行得相當(dāng)不錯,直到你決定需要在該位置上使用另一個計時器類時??赡苓@個類比起默認(rèn)的計時器類提供了更高級的報告方法。 為了實(shí)現(xiàn)這一目標(biāo),你可能會查找應(yīng)用中的所有位置來定位哪些地方使用了定時器類。由于你可能在很多地方都設(shè)置了該類的實(shí)例,以獲取應(yīng)用日常運(yùn)行的性能日志, 這種查找-替換的工作可能會變得相當(dāng)?shù)暮臅r并且錯誤頻發(fā)。這就是服務(wù)的用武之地。

取代了手動創(chuàng)建實(shí)例的操作,我們保留了一個中央控制類來為我們新建實(shí)例。該類的結(jié)構(gòu)相當(dāng)簡單,僅僅包含了一個方法用于調(diào)度我們需要用作服務(wù)的每個類。 該方法只是返回了指定類的一個共享實(shí)例,用于所有依賴該類的地方以服務(wù)的形式來調(diào)用。從而我們可以用以下代碼來取代每次都新建一個實(shí)例的方式:

$timer = \Config\Services::timer();

當(dāng)你想要更改這一實(shí)現(xiàn)時,只需要更改服務(wù)的配置文件,從而在應(yīng)用中就可以自動地進(jìn)行變更替換,不需要任何其他操作。 現(xiàn)在你所需要的只是使用新的替換上來的類的特性,非常地簡單且不易出錯。

注解

我們推薦只在控制器里創(chuàng)建服務(wù)。在其他文件例如模型和庫,應(yīng)當(dāng)依賴于構(gòu)造函數(shù)或者 setter 方法的傳參來實(shí)例化。

便利的方法

有兩個方法被用于獲取一個服務(wù),這些方法都非常的方便。

第一個就是 service() 方法,該方法返回了指定服務(wù)的新的實(shí)例。唯一需要的參數(shù)就是服務(wù)名。 該方法與服務(wù)文件內(nèi)部返回共享實(shí)例的方式是一樣的,因此對該方法的多次調(diào)用總是會返回一個相同的實(shí)例:

$logger = service('logger');

如果創(chuàng)建的方法需要額外的參數(shù),那么這些參數(shù)就應(yīng)該在服務(wù)名后傳遞:

$renderer = service('renderer', APPPATH.'views/');

第二個方法 single_service() ,和 service() 一樣調(diào)用,不過每次都會返回一個指定類的新的實(shí)例:

$logger = single_service('logger');

定義服務(wù)

為了保證服務(wù)的正常運(yùn)行,你需要能夠?qū)γ總€擁有常量API,或者實(shí)現(xiàn)了 接口 的類建立依賴。 CodeIgniter 的大部分類都提供了一個它們所應(yīng)當(dāng)提供的接口。當(dāng)你需要擴(kuò)展或者替代核心類時,你只需要確保自己符合這些接口的要求并且確定這些類的功能是完善的。

舉例來說, RouterCollection 類實(shí)現(xiàn)了 RouterCollectionInterface 接口。當(dāng)你想要替代該類,并實(shí)現(xiàn)不同的路由管理方法時,只需要創(chuàng)建一個實(shí)現(xiàn)了 RouterCollectionInterface 接口的類即可:

class MyRouter implements \CodeIgniter\Router\RouteCollectionInterface
{
        // Implement required methods here.
}

最后,修改 /app/Config/Services.php 以創(chuàng)建 MyRouter 類的實(shí)例,來替代 CodeIgniter\Router\RouterCollection

public static function routes()
{
        return new \App\Router\MyRouter();
}

允許使用參數(shù)

在某些情況下,你可能想要使用某個選項(xiàng)來為一個類在實(shí)例化的時候傳遞配置信息。 由于服務(wù)文件只是簡單的類文件,如上操作非常方便。

renderer 服務(wù)就是一個不錯的例子。默認(rèn)情況下,我們需要該類能夠找到 APPPATH.views/ 目錄下的視圖文件。我們同時也想為開發(fā)者提供改變路徑的選項(xiàng)(如果他們需要的話)。 因此該類接受 $viewPath 變量作為構(gòu)造函數(shù)的參數(shù)。該服務(wù)的調(diào)用方法可能如下所示:

public static function renderer($viewPath=APPPATH.'views/')
{
        return new \CodeIgniter\View\View($viewPath);
}

這一過程在構(gòu)造函數(shù)方法里設(shè)置了默認(rèn)路徑,同時也可以輕松地改變其所使用的路徑:

$renderer = \Config\Services::renderer('/shared/views');

共享類

某些情況下你可能只需要創(chuàng)建一個類的單實(shí)例。該操作可以通過工廠方法內(nèi)部調(diào)用的 getSharedInstance() 方法來輕松地處理。 該方法檢查了該類是否已創(chuàng)建了存儲于內(nèi)部的單個實(shí)例,如果沒有的話,就會創(chuàng)建一個新的。所有的工廠方法都會提供一個 $getShared = true 的值作為最后的參數(shù)。你可以像這樣操作該方法:

class Services
{
    public static function routes($getShared = false)
    {
        if (! $getShared)
        {
            return new \CodeIgniter\Router\RouteCollection();
        }


        return static::getSharedInstance('routes');
    }
}

服務(wù)發(fā)現(xiàn)

CodeIgniter可以自動發(fā)現(xiàn)所有你在其他命名空間里可能定義的 Config\Services.php 文件。這一功能允許了任何模塊服務(wù)化文件的簡單使用。 為了這些定制化的服務(wù)文件可以被自動發(fā)現(xiàn),他們需要滿足這些要求

  • 它們的命名空間必須在 Config\Autoload.php 中已定義
  • 在命名空間內(nèi)部,該文件必須可以在 Config\Services.php 里被找到
  • 它們必須繼承 CodeIgniter\Config\BaseService

一個小例子可以幫助我們更好地理解。

假設(shè)你創(chuàng)建了一個新的目錄,比如在根目錄下的一個叫做 Blog 的目錄。該目錄中里有一個 博客模塊 ,并含有控制器,模型等文件。 如果你愿意的話也可以將某些類作為服務(wù)而使用。第一步就是創(chuàng)建一個新的文件: Blog\Config\Services.php ,該文件結(jié)構(gòu)應(yīng)當(dāng)如下所示:

<?php namespace Blog\Config;


use CodeIgniter\Config\BaseService;


class Services extends BaseService
{
    public static function postManager()
    {
        ...
    }
}

現(xiàn)在你可以使用如上描述的文件。每當(dāng)你想要調(diào)用其他控制器的 posts 服務(wù)時,就可以簡單地使用該框架的 Config\Services 類來獲取你所需要的服務(wù):

$postManager = Config\Services::postManager();

注解

如果多個服務(wù)文件擁有相同的方法名,那么第一個被發(fā)現(xiàn)的服務(wù)實(shí)例就會作為返回值。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號