Php 函数数组的替代方案?

Php 函数数组的替代方案?,php,arrays,function,functional-programming,Php,Arrays,Function,Functional Programming,我正在编写一个应用程序(php),它需要一长串类似但不同的函数,这些函数由一组键调用: $functions = [ "do this" => function() { // does this }, "do that" => function() { // does that } ] etc. function similar_functions($key) { switch ($key) {

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

$functions = [
    "do this" => function() {
        // does this
    },
    "do that" => function() {
        // does that
    }
] 
etc.
function similar_functions($key) {
    switch ($key) {
        case "do this":
            // does this
        break;
        case "do that":
            // does that
        break;
    }
}
我选择将相似的函数放在一个数组中,因为它们不够相似,用一个充满条件语句的大函数得到相同的结果是行不通的。而且我确实需要能够仅通过键调用它们,例如:

$program = ["do this", "do that", "do this"];
foreach ($program as $k => $v) {
    $functions[$v]();
}
这个函数数组结构导致了很多问题,例如,我很难从另一个数组函数中调用一个数组函数,例如,这不起作用:

"do that" => function() {
    $functions["do this"]();
}
这也不是:

"do that" => function() {
    global $functions;
    $functions["do this"]();
}
或者这个:

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

$functions["do that"]($functions);
我想我可以有一个带有长开关语句的巨大函数:

$functions = [
    "do this" => function() {
        // does this
    },
    "do that" => function() {
        // does that
    }
] 
etc.
function similar_functions($key) {
    switch ($key) {
        case "do this":
            // does this
        break;
        case "do that":
            // does that
        break;
    }
}
但这看起来并不是一个好的做法。或许是这样


那么,我的备选方案是什么?我应该采用交换机结构吗?或者还有其他更好的解决方案吗?

带有长
开关
语句的巨型函数更好,因为它允许您调用
类似的函数(“做这个”)
,作为
类似的函数(“做那个”)
的一部分:


您可以用一种更简洁的方式来实现,也就是说,将所有这些函数封装到一个类中。它们可以是静态的,也可以是动态的,我想在这种情况下没什么关系。我将展示这两个例子

1。动态方法

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();
}
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();
}
2。静态方法

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();
}
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();
}

这比在闭包数组中实现这些函数更干净。。。而且比实现一个
开关
更好,因为您仍然需要在循环中调用它-那么为什么使用另一个
开关

闭包会降低php的性能和内存利用率。程序编码引发了一个大泥球、意大利面代码和其他反模式。开关结构很难测试,这违反了标准

为了避免冗余,提高可伸缩性和可维护性,您应该更喜欢OOP。这是提供一组可重用功能的最佳实践。 您还可以将代码分为层和模块,以降低复杂性并提高可交换性

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

这里有一个简单的例子。

<?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(); 
}

好的旧命令模式怎么样


或者以一种更优雅的依赖注入方式,您可以这样做:

<?php

interface Command{
    public function execute();
}

class DoThatCommand implements Command{
    public function execute()
    {
        echo "doing that... \n";
    }
}

class DoThisCommand implements Command{
    public function execute(){
        echo "doing this... \n";
    }
}

class DoTheThirdThingCommandThatDependsOnDoThisCommand implements Command{

    public $doThisCommand;

    public function __construct(DoThisCommand $doThisCommand)
    {
        $this->doThisCommand = $doThisCommand; 
    }

    public function execute()
    {
        echo "doing the ThirdThingCommand that depends on DoThisCommand... \n";
        $this->doThisCommand->execute();
    }
}

$command1 = new DoThatCommand(); 
$command2 = new DoThisCommand();
$command3 = new DoTheThirdThingCommandThatDependsOnDoThisCommand($command2);


$program = [$command1, $command2, $command3];
echo "<pre>";
foreach ($program as $command) {
    $command->execute();
}
?>

我完全赞成中的描述,但我确实想给您一个“快速修复”:

我认为这是不言自明的。

可能类似于:


这样,您可以在
$functions
中定义一个具有函数名和参数值的数组(如果该特定函数需要)。

从另一个数组函数中调用一个数组函数将不起作用,因为
$functions
只有在完全计算RHS.Store之后才会分配其值函数名,然后将变量用作函数<代码>$func=$functions[$v]$func()动态方法违反了单一责任原则,并成长为一个神职人员。静态方法不是全局状态的选项。我理解你的评论,我同意你的观点,但另一方面,你也应该思考这个问题和问题——正如你所看到的,问题本身是由错误的架构或错误的方法引起的。无论如何,我找不到解决方案应该与单元测试一起工作,也不应该遵循SRP的要求。问题是“.我的替代方案是什么?还有其他更好的解决方案吗?”。您的解决方案比Roy的方法更好,但除了重用函数之外,还有相同的问题。添加新功能怎么样?有很多依赖关系的函数呢?需要参数的函数呢?如果你必须解决这些问题,你必须重构一切。在静态方法中,没有人知道谁可以改变状态。我认为,如果问题是由错误的体系结构引起的,你甚至可以通过良好的设计来解决问题。将问题转移到一个对象并不是更好,而是更好方法的第一步:)好的,我再次同意,但我提供的解决方案比闭包数组更好,而且只是从问题本身出发(他目前的设置使用闭包数组)很明显,不可能拥有和解决依赖关系,也不可能调用具有不同参数的函数。如果他的设置是在闭包数组上运行的,那么只需稍加修改并更改为一个类就可以了。有时,在一个类中包含20-30个方法会更好(在一个地方)然后在不需要解决依赖项的情况下拥有20-30个类…Switch语句很难测试,并且违反了OpenClosed原则。这是最好的答案,除了示例中的语法错误:)“do”不能用作方法名!Upps..我将其重命名为“execute”。感谢您的提示;)回答得真不错。我没有提到主题,但我使用了类似的方法将不同应用程序中的类公开给我为其构建的应用程序。它在不浪费内存的情况下工作得很好。顺便问一下,当OOP还有其他约定时,你为什么要说服人们使用SOLID,例如,我应该至少提到一个约定吗。有什么比GRASP更可靠?GRASP是一种非常好的方法,就像领域驱动设计一样。但我认为GRASP或DDD需要坚实的原则。GRAP和DDD的目标是降低复杂性和提高快速上市时间等。在本例中,我指的是SOLID,以关注provi的具体违规行为