OptionsResolver组件

编辑本页

警告:您正在浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 3.2,现已不再维护。

本页的更新版本用于Sy欧宝娱乐app下载地址mfony 6.2(当前稳定版本)。

OptionsResolver组件

OptionsResolver组件是array_replace类固醇。它允许您创建一个包含必需选项、默认值、验证(类型、值)、规范化等的选项系统。

安装

你可以用两种不同的方式安装组件:

然后,要求供应商/ autoload.php文件以启用Composer提供的自动加载机制。否则,您的应用程序将无法找到这个Symfony组件的类。欧宝娱乐app下载地址

使用

想象一下你有一个梅勒类,它有四个选项:宿主用户名密码而且港口

1 2 3 4 5 6 7 8 9
梅勒{受保护的选项公共函数__construct(数组选项=数组(){->选择=选项;}}

访问选择美元,你需要添加大量的样板代码来检查设置了哪些选项:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
梅勒{/ /……公共函数sendMail{邮件=……;邮件->setHost (收取->选项(“主机”]) ?->选项(“主机”]:“smtp.example.org”);邮件->setUsername (收取->选项(“用户名”]) ?->选项(“用户名”]:“用户”);邮件->向setPassword (收取->选项(“密码”]) ?->选项(“密码”]:“爸爸$ $词”);邮件->setPort (收取->选项(“端口”]) ?->选项(“端口”]:25);/ /……}}

这个样板文件很难阅读,而且重复。此外,选项的默认值隐藏在代码的业务逻辑中。使用array_replace要解决这个问题:

12 3 4 5 6 7 8 9 10 11 12 13 14
梅勒{/ /……公共函数__construct(数组选项=数组(){->选项= array_replace(数组“主机”= >“smtp.example.org”“用户名”= >“用户”“密码”= >“爸爸$ $词”“端口”= >25),选项);}}

现在保证所有四个选项都设置好了。但是如果用户梅勒班级犯了错误?

1 2 3
梅勒梅勒(数组“usernme”= >“johndoe”// usernme拼写错误(而不是username)));

不会显示错误。在最好的情况下,bug会在测试过程中出现,但开发人员会花时间寻找问题。在最坏的情况下,bug可能直到部署到活动系统中才会出现。

幸运的是,OptionsResolver类帮助您解决这个问题:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
使用欧宝娱乐app下载地址组件OptionsResolverOptionsResolver梅勒{/ /……公共函数__construct(数组选项=数组(){解析器OptionsResolver ();解析器->setDefaults (数组“主机”= >“smtp.example.org”“用户名”= >“用户”“密码”= >“爸爸$ $词”“端口”= >25));->选择=解析器->解决(选项);}}

像以前一样,所有选项都将被保证设置。此外,一个UndefinedOptionsException如果传递了未知选项,则引发:

1 2 3 4 5 6
梅勒梅勒(数组“usernme”= >“johndoe”));// UndefinedOptionsException: The option "usernme"不存在。//已知选项为:"host", "password", "port", "username"

其余的代码可以在没有样板代码的情况下访问选项的值:

12 3 4 5 6 7 8 9 10 11 12 13 14 15
/ /……梅勒{/ /……公共函数sendMail{邮件=……;邮件->setHost (->选项(“主机”]);邮件->setUsername (->选项(“用户名”]);邮件->向setPassword (->选项(“密码”]);邮件->setPort (->选项(“端口”]);/ /……}}

将选项配置拆分为一个单独的方法是一个很好的实践:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/ /……梅勒{/ /……公共函数__construct(数组选项=数组(){解析器OptionsResolver ();->configureOptions (解析器);->选择=解析器->解决(选项);}公共函数configureOptions(OptionsResolver解析器{解析器->setDefaults (数组“主机”= >“smtp.example.org”“用户名”= >“用户”“密码”= >“爸爸$ $词”“端口”= >25“加密”= >));}}

首先,您的代码变得更容易阅读,特别是如果构造函数不仅仅处理选项。其次,子类现在可以重写configureOptions ()调整选项配置的方法:

12 3 4 5 6 7 8 9 10 11 12 13
/ /……GoogleMailer扩展梅勒{公共函数configureOptions(OptionsResolver解析器{::configureOptions (解析器);解析器->setDefaults (数组“主机”= >“smtp.google.com”“加密”= >“ssl”));}}

需要选择

如果调用方必须设置一个选项,则将该选项传递给setRequired ()。例如,使宿主您可以选择:

1 2 3 4 5 6 7 8 9 10 11
/ /……梅勒{/ /……公共函数configureOptions(OptionsResolver解析器{/ /……解析器->setRequired (“主机”);}}

如果省略了必选选项,则aMissingOptionsException将被抛出:

1 2 3
梅勒梅勒();// MissingOptionsException:缺少必需的选项“host”。

setRequired ()方法接受单个名称或选项名称数组(如果您有多个必选选项):

1 2 3 4 5 6 7 8 9 10 11
/ /……梅勒{/ /……公共函数configureOptions(OptionsResolver解析器{/ /……解析器->setRequired (数组“主机”“用户名”“密码”));}}

使用isRequired ()以确定是否需要某个选项。你可以使用getRequiredOptions ()检索所有必需选项的名称:

12 3 4 5 6 7 8 9 10 11 12 13 14
/ /……GoogleMailer扩展梅勒{公共函数configureOptions(OptionsResolver解析器{::configureOptions (解析器);如果解析器->isRequired (“主机”)) {/ /……requiredOptions解析器->getRequiredOptions ();}}

如果要检查默认选项中是否仍然缺少必需的选项,可以使用isMissing ()。这和isRequired ()如果已经设置了必需的选项,该方法将返回false:

12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/ /……梅勒{/ /……公共函数configureOptions(OptionsResolver解析器{/ /……解析器->setRequired (“主机”);}}/ /……GoogleMailer扩展梅勒{公共函数configureOptions(OptionsResolver解析器{::configureOptions (解析器);解析器->isRequired (“主机”);// => true解析器->isMissing (“主机”);// => true解析器->setDefault (“主机”“smtp.google.com”);解析器->isRequired (“主机”);// => true解析器->isMissing (“主机”);// => false}}

该方法getMissingOptions ()允许您访问所有缺失选项的名称。

类型验证

您可以对选项运行额外的检查,以确保它们被正确地传递。要验证选项的类型,请调用setAllowedTypes ()

12 3 4 5 6 7 8 9 10 11 12
/ /……梅勒{/ /……公共函数configureOptions(OptionsResolver解析器{/ /……解析器->setAllowedTypes (“主机”“字符串”);解析器->setAllowedTypes (“端口”数组“零”“int”));}}

对于每个选项,可以只定义一种类型,也可以定义可接受类型的数组。您可以传递任何类型is_类型< > ()函数是用PHP定义的。此外,还可以传递完全限定的类名或接口名。

如果你现在传递一个无效的选项,一个InvalidOptionsException抛出:

1 2 3 4 5 6
梅勒梅勒(数组“主机”= >25));// InvalidOptionsException:值为25的选项“host”是//类型为string

在子类中,您可以使用addAllowedTypes ()添加其他允许的类型,而不删除已设置的类型。

值验证

有些选项只能接受固定的预定义值列表中的一个。例如,假设梅勒类有一个运输选项,可以是其中之一sendmail邮件而且smtp。使用方法setAllowedValues ()验证所传递的选项是否包含以下值之一:

12 3 4 5 6 7 8 9 10 11 12
/ /……梅勒{/ /……公共函数configureOptions(OptionsResolver解析器{/ /……解析器->setDefault (“交通”“发送邮件”);解析器->setAllowedValues (“交通”数组“发送邮件”“邮件”“smtp”));}}

如果你通过了一个无效的传输,一个InvalidOptionsException抛出:

1 2 3 4 5 6
梅勒梅勒(数组“交通”= >“发送邮件”));// InvalidOptionsException:选项"transport"有这个值// "send-mail",但期望是"sendmail", "mail", "smtp"之一

对于具有更复杂验证方案的选项,传递一个返回的闭包真正的对于可接受的值和对于无效值:

1 2 3 4
/ /……解析器->setAllowedValues (“交通”函数价值{//返回true或false});

在子类中,您可以使用addAllowedValues ()添加额外的允许值,而不删除已设置的值。

选择归一化

有时,在使用选项值之前,需要对它们进行规范化。例如,假设宿主应该总是以http://。为此,您可以编写规范化程序。标准化器在验证一个选项之后执行。可以通过调用来配置规范化器setNormalizer ()

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
使用欧宝娱乐app下载地址组件OptionsResolver选项/ /……梅勒{/ /……公共函数configureOptions(OptionsResolver解析器{/ /……解析器->setNormalizer (“主机”函数(选项选项价值{如果“http://”! = = substr (价值07)) {价值“http://”价值;}返回价值;});}}

规范化器接收实际值美元的价值并返回规范化的形式。你可以看到闭包也需要选择美元参数。如果你需要在规范化过程中使用其他选项,这是很有用的:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
/ /……梅勒{/ /……公共函数configureOptions(OptionsResolver解析器{/ /……解析器->setNormalizer (“主机”函数(选项选项价值{如果“http://”! = = substr (价值07) & &“https://”! = = substr (价值08)) {如果“ssl”= = =选项(“加密”) {价值“https://”价值;}其他的{价值“http://”价值;}}返回价值;});}}

依赖于其他选项的默认值

属性的默认值港口方法的用户所选择的加密梅勒类。更准确地说,您希望将端口设置为465如果使用SSL和25否则。

类的默认值传递闭包来实现此特性港口选择。闭包接收选项作为参数。基于这些选项,您可以返回所需的默认值:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
使用欧宝娱乐app下载地址组件OptionsResolver选项/ /……梅勒{/ /……公共函数configureOptions(OptionsResolver解析器{/ /……解析器->setDefault (“加密”);解析器->setDefault (“端口”函数(选项选项{如果“ssl”= = =选项(“加密”) {返回465;}返回25;});}}

谨慎

可调用对象的实参必须是类型提示为选项。否则,可调用对象本身被视为该选项的默认值。

请注意

对象时才执行闭包港口选项不是由用户设置,也不是在子类中覆盖。

之前设置的默认值可以通过在闭包中添加第二个参数来访问:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/ /……梅勒{/ /……公共函数configureOptions(OptionsResolver解析器{/ /……解析器->setDefaults (数组“加密”= >“主机”= >“example.org”));}}GoogleMailer扩展梅勒{公共函数configureOptions(OptionsResolver解析器{::configureOptions (解析器);解析器->setDefault (“主机”函数(选项选项previousValue{如果“ssl”= = =选项(“加密”) {返回“secure.example.org”//获取基类中配置的默认值返回previousValue;});}}

如示例所示,如果您想在子类中重用父类中设置的默认值,则此特性非常有用。

没有默认值的选项

在某些情况下,定义一个选项而不设置默认值是有用的。如果您需要知道用户是否实际上是否设置一个选项。例如,如果你为一个选项设置了默认值,不可能知道用户是否传递了这个值,或者它只是来自默认值:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
/ /……梅勒{/ /……公共函数configureOptions(OptionsResolver解析器{/ /……解析器->setDefault (“端口”25);}/ /……公共函数sendMail{//这是默认值还是类的调用者真的//设置端口为25?如果25= = =->选项(“端口”) {/ /……}}}

你可以使用setDefined ()定义一个选项而不设置默认值。然后,只有在实际传递给时,该选项才会包含在已解析的选项中解决()

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/ /……梅勒{/ /……公共函数configureOptions(OptionsResolver解析器{/ /……解析器->setDefined (“端口”);}/ /……公共函数sendMail{如果(array_key_exists (“端口”->选项)){回声“集合!”;}其他的{回声“没有!”;}}}梅勒梅勒();梅勒->sendMail ();// =>未设置!梅勒梅勒(数组“端口”= >25));梅勒->sendMail ();// =>设置!

如果你想一次性定义多个选项,你也可以传递一个选项名称数组:

1 2 3 4 5 6 7 8 9 10
/ /……梅勒{/ /……公共函数configureOptions(OptionsResolver解析器{/ /……解析器->setDefined (数组“端口”“加密”));}}

的方法isDefined ()而且getDefinedOptions ()让您了解定义了哪些选项:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
/ /……GoogleMailer扩展梅勒{/ /……公共函数configureOptions(OptionsResolver解析器{::configureOptions (解析器);如果解析器->isDefined (“主机”)) {//下面的一个被调用:// $resolver->setDefault('host',…);/ /解析器- > setRequired('主机');/ /解析器- > setDefined('主机');definedOptions解析器->getDefinedOptions ();}}

性能调整

对于当前的实现,configureOptions ()方法的每个实例都将调用梅勒类。根据选项配置的数量和创建实例的数量,这可能会给应用程序增加明显的开销。如果这个开销成为一个问题,你可以改变你的代码,每个类只做一次配置:

12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/ /……梅勒{私人静态resolversByClass数组();受保护的选项公共函数__construct(数组选项=数组(){//这是什么类型的Mailer, Mailer, GoogleMailer,…?= get_class ();// configureOptions()在这个类之前执行了吗?如果(!收取自我:: $resolversByClass [))) {自我:: $resolversByClass [] =OptionsResolver ();->configureOptions (自我:: $resolversByClass []);}->选择=自我:: $resolversByClass [->解决(选项);}公共函数configureOptions(OptionsResolver解析器{/ /……}}

现在,OptionsResolver实例将在每个类中创建一次,并从那时开始重用。注意,如果默认选项包含对对象或对象图的引用,这可能会导致长时间运行的应用程序发生内存泄漏。如果是这样的话,实现一个方法clearOptionsConfig ()并定期调用它:

12 3 4 5 6 7 8 9 10 11 12
/ /……梅勒{私人静态resolversByClass数组();公共静态函数clearOptionsConfig(){自我:: $resolversByClass =数组();}/ /……

就是这样!现在您已经拥有了轻松处理代码中的选项所需的所有工具和知识。

此工作,包括代码示例,是根据创作共用BY-SA 3.0许可证。