跳到內容

如何建立服務別名並將服務標記為私有

編輯此頁面

將服務標記為公開 / 私有

當定義服務時,可以將其設為公開或私有。如果服務是公開的,則表示您可以在執行時直接從容器存取它。例如,doctrine 服務是一個公開服務

1
2
// only public services can be accessed in this way
$doctrine = $container->get('doctrine');

但通常服務是透過依賴注入來存取。在這種情況下,這些服務不需要是公開的。

因此,除非您明確需要透過 $container->get() 直接從容器存取服務,否則最佳實務是將您的服務設為私有。事實上,所有服務預設都是私有的

您也可以在每個服務的基礎上控制 public 選項

1
2
3
4
5
6
# config/services.yaml
services:
    # ...

    App\Service\Foo:
        public: true

也可以透過 #[Autoconfigure] 屬性將服務定義為公開。此屬性必須直接用於您要設定的服務類別上

1
2
3
4
5
6
7
8
9
10
// src/Service/Foo.php
namespace App\Service;

use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;

#[Autoconfigure(public: true)]
class Foo
{
    // ...
}

私有服務很特別,因為它們允許容器優化是否以及如何實例化它們。這提高了容器的效能。它也為您提供了更好的錯誤訊息:如果您嘗試參考不存在的服務,即使有問題的程式碼不會在該頁面上執行,當您重新整理任何頁面時,您都會收到明確的錯誤訊息。

現在服務是私有的,您絕不能直接從容器中獲取服務

1
2
3
use App\Service\Foo;

$container->get(Foo::class);

因此,如果您不想直接從您的程式碼存取服務,則可以將服務標記為私有。但是,如果服務已被標記為私有,您仍然可以為其建立別名(請參閱下文)以存取此服務(透過別名)。

別名

您有時可能想要使用捷徑來存取某些服務。您可以透過為它們建立別名來做到這一點,而且,您甚至可以為非公開服務建立別名。

1
2
3
4
5
6
7
8
9
10
11
// src/Mail/PhpMailer.php
namespace App\Mail;

// ...
use Symfony\Component\DependencyInjection\Attribute\AsAlias;

#[AsAlias(id: 'app.mailer', public: true)]
class PhpMailer
{
    // ...
}

這表示當直接使用容器時,您可以透過請求 app.mailer 服務來存取 PhpMailer 服務,就像這樣

1
$container->get('app.mailer'); // Would return a PhpMailer instance

提示

在 YAML 中,您也可以使用捷徑來為服務建立別名

1
2
3
4
# config/services.yaml
services:
    # ...
    app.mailer: '@App\Mail\PhpMailer'

提示

當使用 #[AsAlias] 屬性時,如果類別僅實作一個介面,您可以省略傳遞 id 參數。MailerInterface 將會是 PhpMailer 的別名

1
2
3
4
5
6
7
8
9
10
11
12
// src/Mail/PhpMailer.php
namespace App\Mail;

// ...
use Symfony\Component\DependencyInjection\Attribute\AsAlias;
use Symfony\Component\Mailer\MailerInterface;

#[AsAlias]
class PhpMailer implements MailerInterface
{
    // ...
}

棄用服務別名

如果您決定棄用服務別名的使用(因為它已過時或您決定不再維護它),您可以棄用其定義

1
2
3
4
5
6
7
8
9
10
11
12
13
14
app.mailer:
    alias: 'App\Mail\PhpMailer'

    # this outputs the following generic deprecation message:
    # Since acme/package 1.2: The "app.mailer" service alias is deprecated. You should stop using it, as it will be removed in the future
    deprecated:
        package: 'acme/package'
        version: '1.2'

    # you can also define a custom deprecation message (%alias_id% placeholder is available)
    deprecated:
        package: 'acme/package'
        version: '1.2'
        message: 'The "%alias_id%" alias is deprecated. Do not use it anymore.'

現在,每次使用此服務別名時,都會觸發棄用警告,建議您停止或變更您對該別名的使用。

該訊息實際上是一個訊息範本,它將 %alias_id% 預留位置的出現次數替換為服務別名 id。您的範本中必須至少有一個 %alias_id% 預留位置。

匿名服務

在某些情況下,您可能想要防止服務被用作其他服務的依賴項。這可以透過建立匿名服務來實現。這些服務就像常規服務,但它們不定義 ID,並且在它們被使用的地方建立。

以下範例示範如何將匿名服務注入到另一個服務中

1
2
3
4
5
6
# config/services.yaml
services:
    App\Foo:
        arguments:
            - !service
                class: App\AnonymousBar

注意

匿名服務不會繼承從組態中定義的預設值提供的定義。因此,當執行匿名服務時,您需要明確地將服務標記為自動連線或自動設定,例如:inline_service(Foo::class)->autowire()->autoconfigure()

將匿名服務用作工廠看起來像這樣

1
2
3
4
# config/services.yaml
services:
    App\Foo:
        factory: [ !service { class: App\FooFactory }, 'constructFoo' ]

棄用服務

一旦您決定棄用服務的使用(因為它已過時或您決定不再維護它),您可以棄用其定義

1
2
3
4
5
6
# config/services.yaml
App\Service\OldService:
    deprecated:
        package: 'vendor-name/package-name'
        version: '2.8'
        message: The "%service_id%" service is deprecated since vendor-name/package-name 2.8 and will be removed in 3.0.

現在,每次使用此服務時,都會觸發棄用警告,建議您停止或變更您對該服務的使用。

該訊息實際上是一個訊息範本,它將 %service_id% 預留位置的出現次數替換為服務的 id。您的範本中必須至少有一個 %service_id% 預留位置。

注意

棄用訊息是選填的。如果未設定,Symfony 將顯示此預設訊息:「%service_id%」服務已棄用。您應該停止使用它,因為它很快就會被移除。.

提示

強烈建議您定義自訂訊息,因為預設訊息太過於通用。一個好的訊息會告知此服務何時被棄用、將維護到何時以及要使用的替代服務(如果有的話)。

對於服務裝飾器(請參閱如何裝飾服務),如果定義未修改棄用狀態,它將從被裝飾的定義繼承狀態。

本作品,包括程式碼範例,皆以創用 CC BY-SA 3.0 授權條款授權。
目錄
    版本