php 如何从服务访问应用程序参数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11209529/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to access an application parameters from a service?
提问by Pierre de LESPINAY
From my controllers, I access the application parameters (those in /app/config) with
从我的控制器中,我访问应用程序参数(在 中的那些/app/config)
$this->container->getParameter('my_param')
But I don't know how to access it from a service (I imagine my service class is not supposed to extend Symfony\Bundle\FrameworkBundle\Controller\Controller).
但我不知道如何从服务访问它(我想我的服务类不应该扩展Symfony\Bundle\FrameworkBundle\Controller\Controller)。
Should I map needed parameters into my service registration like this:
我是否应该像这样将所需的参数映射到我的服务注册中:
#src/Me/MyBundle/Service/my_service/service.yml
parameters:
my_param1: %my_param1%
my_param2: %my_param2%
my_param3: %my_param3%
or something similar? How should I access to my application parameters from a service?
或类似的东西?我应该如何从服务访问我的应用程序参数?
This questionseems like the same but mine actually answers to it (parameters from a controller), I'm talking about accessing from a service.
这个问题似乎是一样的,但我的实际答案是(来自控制器的参数),我说的是从服务访问。
回答by richsage
You can pass parameters to your service in the same way as you inject other services, by specifying them in your service definition. For example, in YAML:
您可以通过在服务定义中指定参数,以与注入其他服务相同的方式将参数传递给您的服务。例如,在 YAML 中:
services:
my_service:
class: My\Bundle\Service\MyService
arguments: [%my_param1%, %my_param2%]
where the %my_param1%etc corresponds to a parameter named my_param1. Then your service class constructor could then be:
其中%my_param1%etc 对应于名为my_param1. 那么你的服务类构造函数可以是:
public function __construct($myParam1, $myParam2)
{
// ...
}
回答by Tomá? Votruba
The Clean Way 2018
清洁之路 2018
Since 2017 and Symfony 3.4there is much cleaner way - easy to setup and use.
自 2017 年和 Symfony 3.4 以来,有更简洁的方法 - 易于设置和使用。
Instead of using container and service/parameter locator anti-pattern, you can pass parameters to class via it's constructor. Don't worry, it's not time-demanding work, but rather setup once & forgetapproach.
您可以通过类的构造函数将参数传递给类,而不是使用容器和服务/参数定位器反模式。别担心,这不是耗时的工作,而是设置一次并忘记的方法。
How to set it up in 2 steps?
如何分两步设置?
1. config.yml
1. config.yml
# config.yml
parameters:
api_pass: 'secret_password'
api_user: 'my_name'
services:
_defaults:
autowire: true
bind:
$apiPass: '%api_pass%'
$apiUser: '%api_user%'
App\:
resource: ..
2. Any Controller
2. 任何 Controller
<?php declare(strict_types=1);
final class ApiController extends SymfonyController
{
/**
* @var string
*/
private $apiPass;
/**
* @var string
*/
private $apiUser;
public function __construct(string $apiPass, string $apiUser)
{
$this->apiPass = $apiPass;
$this->apiUser = $apiUser;
}
public function registerAction(): void
{
var_dump($this->apiPass); // "secret_password"
var_dump($this->apiUser); // "my_name"
}
}
Instant Upgrade Ready!
即时升级准备就绪!
In case you use older approach, you can automate it with Rector.
如果您使用旧方法,您可以使用 Rector 自动化它。
Read More
阅读更多
This is called constructor injection over services locatorapproach.
这称为服务定位器方法的构造函数注入。
To read more about this, check my post How to Get Parameter in Symfony Controller the Clean Way.
要了解更多相关信息,请查看我的文章How to Get Parameter in Symfony Controller the Clean Way。
(It's tested and I keep it updated for new Symfony major version (5, 6...)).
(它已经过测试,我会为新的 Symfony 主要版本(5、6...)保持更新)。
回答by Ham L.
Instead of mapping your needed parameters one by one, why not allowing your service to access the container directly? Doing so, you do not have to update your mapping if there is new parameters added (which relate to your service).
与其一一映射你需要的参数,为什么不让你的服务直接访问容器呢?这样做,如果添加了新参数(与您的服务相关),则不必更新映射。
To do so:
这样做:
Make following changes to your service class
对您的服务类进行以下更改
use Symfony\Component\DependencyInjection\ContainerInterface; // <- Add this
class MyServiceClass
{
private $container; // <- Add this
public function __construct(ContainerInterface $container) // <- Add this
{
$this->container = $container;
}
public function doSomething()
{
$this->container->getParameter('param_name_1'); // <- Access your param
}
}
Add @service_container as "arguments" in your services.yml
在 services.yml 中添加 @service_container 作为“参数”
services:
my_service_id:
class: ...\MyServiceClass
arguments: ["@service_container"] // <- Add this
回答by Dave
As solution to some of issues mentioned, I define an array parameter then inject it. Adding a new parameter later just requires addition to parameter array without any change to service_container arguments or construct.
作为提到的一些问题的解决方案,我定义了一个数组参数然后注入它。稍后添加新参数只需要添加到参数数组,而无需对 service_container 参数或构造进行任何更改。
So extending on @richsage answer:
所以扩展@richsage 答案:
parameters.yml
参数.yml
parameters:
array_param_name:
param_name_1: "value"
param_name_2: "value"
services.yml
服务.yml
services:
my_service:
class: My\Bundle\Service\MyService
arguments: [%array_param_name%]
Then access inside class
然后访问内部类
public function __construct($params)
{
$this->param1 = array_key_exists('param_name_1',$params)
? $params['param_name_1'] : null;
// ...
}
回答by Carol-Theodor Pelu
With Symfony 4.1the solution is quite simple.
随着Symfony的4.1的解决方案是非常简单的。
Here is a snippet from the original post:
这是原始帖子的片段:
// src/Service/MessageGenerator.php
// ...
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
class MessageGenerator
{
private $params;
public function __construct(ParameterBagInterface $params)
{
$this->params = $params;
}
public function someMethod()
{
$parameterValue = $this->params->get('parameter_name');
// ...
}
}
Link to the original post: https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service
原文链接:https: //symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service
回答by Ousmane
There is a very clean new way to achieve it since symfony 4.1
自 symfony 4.1 以来,有一种非常干净的新方法来实现它
<?php
// src/Service/MessageGeneratorService.php
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
class MessageGeneratorService
{
private $params;
public function __construct(ParameterBagInterface $params)
{
$this->params = $params;
}
public function someMethod()
{
$parameterValue = $this->params->get('parameter_name');
...
}
}
source : https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service.
来源:https: //symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service。
回答by Dung
@richsage is correct (for Symfony 3.?) but it did not work for my Symfony 4.x. So here is for Symfony 4.
@richsage 是正确的(对于 Symfony 3.?)但它不适用于我的 Symfony 4.x。所以这里是 Symfony 4。
in services.yaml file
在 services.yaml 文件中
parameters:
param1: 'hello'
Services:
App\Service\routineCheck:
arguments:
$toBechecked: '%param1%' # argument must match in class constructor
in your service class routineCheck.php file do constructor like so
在您的服务类routineCheck.php 文件中,像这样做构造函数
private $toBechecked;
public function __construct($toBechecked)
{
$this->toBechecked = $toBechecked;
}
public function echoSomething()
{
echo $this->toBechecked;
}
Done.
完毕。
回答by shades3002
In symfony 4, we can access the parameters by means of dependency injection:
在symfony 4中,我们可以通过依赖注入的方式访问参数:
Services:
服务:
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
MyServices {
protected $container;
protected $path;
public function __construct(Container $container)
{
$this->container = $container;
$this->path = $this->container->getParameter('upload_directory');
}
}
parameters.yml:
参数.yml:
parameters:
upload_directory: '%kernel.project_dir%/public/uploads'
回答by Dan Costinel
Symfony 3.4 here.
Symfony 3.4 在这里。
After some researches, I don't think passing parameters to a class/service via it's constructor, is always a good idea. Imagine if you need to pass to a controller/service some more parameters than 2 or 3. What then? Would be ridiculous to pass, let's say, up to 10 parameters.
经过一些研究,我不认为通过它的构造函数将参数传递给类/服务总是一个好主意。想象一下,如果您需要向控制器/服务传递比 2 或 3 个更多的参数。然后呢?比方说,最多传递 10 个参数会很荒谬。
Instead, use the ParameterBagclass as a dependency, when declaring the service in yml, and then use as many parameters as you wish.
相反,ParameterBag在 yml 中声明服务时,使用该类作为依赖项,然后根据需要使用尽可能多的参数。
A concrete example, let's say you have a mailer service, like PHPMailer, and you want to have the PHPMailer connection parameters in the paramters.ymlfile:
一个具体的例子,假设你有一个邮件服务,比如 PHPMailer,并且你想要在paramters.yml文件中包含 PHPMailer 连接参数:
#parameters.yml
parameters:
mail_admin: [email protected]
mail_host: mail.abc.com
mail_username: [email protected]
mail_password: pass
mail_from: [email protected]
mail_from_name: [email protected]
mail_smtp_secure: 'ssl'
mail_port: 465
#services.yml
services:
app.php_mailer:
class: AppBundle\Services\PHPMailerService
arguments: ['@assetic.parameter_bag'] #here one could have other services to be injected
public: true
# AppBundle\Services\PHPMailerService.php
...
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
...
class PHPMailerService
{
private $parameterBag;
private $mailAdmin;
private $mailHost;
private $mailUsername;
private $mailPassword;
private $mailFrom;
private $mailFromName;
private $mailSMTPSecure;
private $mailPort;
}
public function __construct(ParameterBag $parameterBag)
{
$this->parameterBag = $parameterBag;
$this->mailAdmin = $this->parameterBag->get('mail_admin');
$this->mailHost = $this->parameterBag->get('mail_host');
$this->mailUsername = $this->parameterBag->get('mail_username');
$this->mailPassword = $this->parameterBag->get('mail_password');
$this->mailFrom = $this->parameterBag->get('mail_from');
$this->mailFromName = $this->parameterBag->get('mail_from_name');
$this->mailSMTPSecure = $this->parameterBag->get('mail_smtp_secure');
$this->mailPort = $this->parameterBag->get('mail_port');
}
public function sendEmail()
{
//...
}
I think this is a better way.
我认为这是一个更好的方法。

