如何建立服務別名並將服務標記為私有
將服務標記為公開 / 私有
當定義服務時,可以將其設為公開或私有。如果服務是公開的,則表示您可以在執行時直接從容器存取它。例如,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%
」服務已棄用。您應該停止使用它,因為它很快就會被移除。.
提示
強烈建議您定義自訂訊息,因為預設訊息太過於通用。一個好的訊息會告知此服務何時被棄用、將維護到何時以及要使用的替代服務(如果有的話)。
對於服務裝飾器(請參閱如何裝飾服務),如果定義未修改棄用狀態,它將從被裝飾的定義繼承狀態。