如果实用程序 class 是反模式,那么 PHP 中的替代方案是什么?
If utility class is an anti pattern, what is the alternatives in PHP?
我正在尝试通过遵循最新的 OOP 设计模式来构建自己的 MVC 框架(当然是为了更好地学习它)。我想知道,放置可重复代码的最佳实践是什么(这些代码用于作为静态方法保留在实用程序 classes 中,这被认为不是一个好的模式)。
例如,我们想使用点分隔字符串遍历一个多维数组,我必须在几个 classes(它们是来自其他基 classes 的子classes 中使用这个算法=16=]es)。如何在不使用实用程序 class 且不多次重复相同代码的情况下做到这一点?
实用程序 class 没有任何问题,只是不要将所有不相关的实用程序函数集中到一个巨大的 class 中。根据它们的作用将它们分开(和命名空间)。例如,参见 Zend Filter or Symfony Filesystem。
或者,如果需要此函数的 class 都有一个共同的父级,您可以将函数放在最顶层 class 或抽象。
或者,如果 class 没有共同的父代,您可以使用名为 extractArrayFromDottedString()
或类似方法的方法创建特征。
Laravel 通过定义独立的 "helper" 函数来做到这一点。 CakePHP 和 Yii 通过使用静态方法定义容器实用程序 classes(即 "Text" 或 "Xml")来实现。编程语言做类似的事情(即 PHP 的 implode()
、Java 的 Math.round
、C 的 strcpy
、Python 的 sum()
,等等)。几乎所有东西都使用独立函数或静态 class 方法。
最终,最好的选择是主观。这取决于你想要如何组织事物。研究 PHP 中的常见设计模式,感受不同框架在实践中的感受。然后选择一种方法并保持一致。
Utility class is an anti pattern
真的没有。
在 OOP 中,使用实用程序 classes 设计整个应用程序很可能是一种反模式,但使用提供 routine/transverse 任务的 static
方法定义实用程序 classes 可能是有意义的。
不将实用程序方法与使用它们的现有 classes 的方法混合也可以提供实用程序 class 和消费者 classes 的更好的内聚性和可重用性。
当然,您可以使用实例方法定义 class。
这是有效的,更冗长但具有提高 class 可测试性的优点。如果您需要模拟调用或切换到实用方法的其他实现,则必须优先使用实例方法。
如果这些是实用函数,则在单独的命名空间中定义它们。类似于
<?php
namespace Utils;
function array_query($array, $query) {
// code for traversing the array
}
将它们放在一个或多个文件中就可以了。请记住将该文件包含在您应用程序的 boostrap 阶段。
底线:停止滥用静态 classes,我们现在有用于该垃圾的命名空间。
但是,并非所有您认为的 "utility functions" 都是真实的。如果您开始使用 OOP 代码,一些代码应该放在关联的 classes 中。例如 "email validation" 不应进入 "utility function",而应进入 class:
class EmailAddress {
private $emailAddress;
public function __construct($emailAddress) {
$this->assertValidEmailAddress($emailAddress);
$this->emailAddress = $emailAddress;
}
private function assertValidEmailAddress($emailAddress) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new DomainException("Not an email address");
}
}
public function __toString() {
return $this->emailAddress;
}
}
并且这些重复的 "domain logic" 片段应该放在单独的实体中,然后您可以为其他 class 类型提示。然后你在某处使用它作为:
public function register(EmailAddress $email, SafePassword $password): User
{
// your user registration logic
}
通过这种方式,您的各种服务可以执行活动,您可以使用 try-catch
改进验证。
P.S.
You might need to take a hard look at what you are doing. That dotted access utility is neat (I had it too like 10 years ago), but actually is is a "temporary fix" for a deeper problem: you shouldn't be dealing with so deep array, that you need to simplify accessing them.
我正在尝试通过遵循最新的 OOP 设计模式来构建自己的 MVC 框架(当然是为了更好地学习它)。我想知道,放置可重复代码的最佳实践是什么(这些代码用于作为静态方法保留在实用程序 classes 中,这被认为不是一个好的模式)。
例如,我们想使用点分隔字符串遍历一个多维数组,我必须在几个 classes(它们是来自其他基 classes 的子classes 中使用这个算法=16=]es)。如何在不使用实用程序 class 且不多次重复相同代码的情况下做到这一点?
实用程序 class 没有任何问题,只是不要将所有不相关的实用程序函数集中到一个巨大的 class 中。根据它们的作用将它们分开(和命名空间)。例如,参见 Zend Filter or Symfony Filesystem。
或者,如果需要此函数的 class 都有一个共同的父级,您可以将函数放在最顶层 class 或抽象。
或者,如果 class 没有共同的父代,您可以使用名为 extractArrayFromDottedString()
或类似方法的方法创建特征。
Laravel 通过定义独立的 "helper" 函数来做到这一点。 CakePHP 和 Yii 通过使用静态方法定义容器实用程序 classes(即 "Text" 或 "Xml")来实现。编程语言做类似的事情(即 PHP 的 implode()
、Java 的 Math.round
、C 的 strcpy
、Python 的 sum()
,等等)。几乎所有东西都使用独立函数或静态 class 方法。
最终,最好的选择是主观。这取决于你想要如何组织事物。研究 PHP 中的常见设计模式,感受不同框架在实践中的感受。然后选择一种方法并保持一致。
Utility class is an anti pattern
真的没有。
在 OOP 中,使用实用程序 classes 设计整个应用程序很可能是一种反模式,但使用提供 routine/transverse 任务的 static
方法定义实用程序 classes 可能是有意义的。
不将实用程序方法与使用它们的现有 classes 的方法混合也可以提供实用程序 class 和消费者 classes 的更好的内聚性和可重用性。
当然,您可以使用实例方法定义 class。
这是有效的,更冗长但具有提高 class 可测试性的优点。如果您需要模拟调用或切换到实用方法的其他实现,则必须优先使用实例方法。
如果这些是实用函数,则在单独的命名空间中定义它们。类似于
<?php
namespace Utils;
function array_query($array, $query) {
// code for traversing the array
}
将它们放在一个或多个文件中就可以了。请记住将该文件包含在您应用程序的 boostrap 阶段。
底线:停止滥用静态 classes,我们现在有用于该垃圾的命名空间。
但是,并非所有您认为的 "utility functions" 都是真实的。如果您开始使用 OOP 代码,一些代码应该放在关联的 classes 中。例如 "email validation" 不应进入 "utility function",而应进入 class:
class EmailAddress {
private $emailAddress;
public function __construct($emailAddress) {
$this->assertValidEmailAddress($emailAddress);
$this->emailAddress = $emailAddress;
}
private function assertValidEmailAddress($emailAddress) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new DomainException("Not an email address");
}
}
public function __toString() {
return $this->emailAddress;
}
}
并且这些重复的 "domain logic" 片段应该放在单独的实体中,然后您可以为其他 class 类型提示。然后你在某处使用它作为:
public function register(EmailAddress $email, SafePassword $password): User
{
// your user registration logic
}
通过这种方式,您的各种服务可以执行活动,您可以使用 try-catch
改进验证。
P.S.
You might need to take a hard look at what you are doing. That dotted access utility is neat (I had it too like 10 years ago), but actually is is a "temporary fix" for a deeper problem: you shouldn't be dealing with so deep array, that you need to simplify accessing them.