一组函数的替代?

Roy*_*Roy 12 php arrays functional-programming function

我正在编写一个应用程序(php),它需要很长的类似但不同的函数列表,这些函数由一组键调用:

$functions = [
    "do this" => function() {
        // does this
    },
    "do that" => function() {
        // does that
    }
] 
etc.
Run Code Online (Sandbox Code Playgroud)

我选择了将类似的功能在一个数组,因为它们不是类似不够 -让一个大的功能,这是完全有条件的语句相同的结果是不是要去工作.而且我也需要能够仅通过键来调用它们,例如:

$program = ["do this", "do that", "do this"];
foreach ($program as $k => $v) {
    $functions[$v]();
}
Run Code Online (Sandbox Code Playgroud)

事实是这个函数 - 数组结构引起了很多问题,例如我很难从另一个数组函数中调用一个数组函数,例如这不起作用:

"do that" => function() {
    $functions["do this"]();
}
Run Code Online (Sandbox Code Playgroud)

也不是这样

"do that" => function() {
    global $functions;
    $functions["do this"]();
}
Run Code Online (Sandbox Code Playgroud)

或这个:

"do that" => function($functions) {
    $functions["do this"]();
}

$functions["do that"]($functions);
Run Code Online (Sandbox Code Playgroud)

我想我可以有一个带有long switch语句的巨型函数:

function similar_functions($key) {
    switch ($key) {
        case "do this":
            // does this
        break;
        case "do that":
            // does that
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)

但这似乎并不是一种好的做法.或许它是?

那么,我有什么选择呢?我应该选择开关结构吗?还是有另一种更好的解决方案吗?

Mam*_*muz 20

在php中,闭包对于性能和内存耗资来说是昂贵的.程序编码引发了泥球,意大利面条代码和其他反模式的大球.交换机结构很难测试,这违反了OCP.

您应该更喜欢以SOLID方式使用OOP 以避免冗余,从而提高可伸缩性和可维护性.这是提供一组可重复使用的功能的最佳实践.您还可以在层和模块中分离代码,以降低复杂性并提高可互换性.

在您的情况下,您的类可以实现__invoke将其称为invokable,并且您的键可以是这些类的完全限定名称空间,因此您可以像函数一样调用它.从现在开始,您还可以使用继承,多态或复合,装饰等设计模式来重用其他函数或添加函数.

这是一个简单的例子..

<?php
use Foo\Bar;

class This
{
    public function __invoke()
    {
        $this->execute();
    }

    public function execute()
    {
        /* ... */
    }
 }

class That extends This
{
    public function execute()
    {
        /* ... */
    }
 }

$namespaces = array("\Foo\Bar\This", "\Foo\Bar\That"); 
foreach ($namespaces as $fullQualifiedNamespace) {
    /** @var callable $fullQualifiedNamespace */
    $fullQualifiedNamespace(); 
}
Run Code Online (Sandbox Code Playgroud)

通过实现This和That的特定接口也可以访问此行为.在迭代中,您可以检查接口以调用已定义的合同.或者您构建一个Process Class,您可以在其中添加实现此接口的对象.Process类可以执行所有附加对象(Chain of Responsibility).

我更喜欢责任链模式这是大多数开发人员可以理解的,而不像PHP的__invoke拦截器那么神奇.在工厂中,您可以定义链,并且可以定义链或链接对象的其他依赖关系.

  • 这是最好的答案,除了示例中的语法错误:)'do'不能用于方法名称! (4认同)

sha*_*yyx 7

您可以以更干净的方式执行此操作,即将所有这些函数封装到类中.它们可以是静态的也可以是动态的,在这种情况下我猜的并不重要.我将展示两个例子......

动态方法

class MyFunctions
{

    public function doThis()
    {
        /* implement do this here */
    }

    public function doThat()
    {
        /* implement do that here */
    }
    /* ... */
}

/* then somewhere else */
$program = ["doThis", "doThat", "doThis"];
$myFunctions = new MyFunctions;
foreach ($program as $method) {
    $myFunctions->$method();
}
Run Code Online (Sandbox Code Playgroud)

静态方法

class MyFunctions
{

    public static function doThis()
    {
        /* implement do this here */
    }

    public static function doThat()
    {
        /* implement do that here */
    }
    /* ... */
}

/* then somewhere else */
$program = ["doThis", "doThat", "doThis"];
foreach ($program as $method) {
    MyFunctions::$method();
}
Run Code Online (Sandbox Code Playgroud)

恕我直言这比在一个闭包数组中实现这些函数要干净得多......并且比实现一个更好,switch因为你仍然需要在循环中调用它 - 那么为什么要慢下来switch呢?


Sha*_*tta 1

具有长语句的巨型函数switch更好,因为它允许您similar_functions("do this")作为以下内容的一部分进行调用similar_functions("do that")

function similar_functions($key) {
    switch ($key) {
        case "do this":
            // does this
        break;
        case "do that":
            similar_functions("do this");
            // and then does that
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)