一系列函数的替代方案?

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

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

我选择将相似的函数放在一个数组中,因为它们不相似足够 - 使用一个充满条件语句的大函数获得相同的结果是行不通的。并且我确实需要能够通过密钥来调用它们,例如:

$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);

我想我可以使用一个很长的开关语句的巨型函数:

function similar_functions($key) {
    switch ($key) {
        case "do this":
           //does this
        break;
        case "do that":
           //does that
        break;
    }
}

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

So, what are my alternatives? Should I go with the switch structure? Or is there another, better solution?

1
有人可以解释为什么那些不起作用的例子不起作用?答案侧重于更好的解决方案,但我不明白为什么原始代码不起作用。
额外 作者 user8669,
你想在这里解决的更高级问题是什么?为什么在名称中调用的数组中需要这么多函数?
额外 作者 xirt,
我的猜测是有一个更好的方法,但没有更多的信息很难说。你能发布一些关于你希望功能完成的更多细节吗? (即一些具体的例子)
额外 作者 paul,
@Roy作为lortabac说,即使你想让它们在一个数组中,你应该能够在数组之外定义它们,然后用指向函数的指针构造数组,而不是使用定义。
额外 作者 paul,
@lortabac我发布了一条扩展你评论的答案,我希望你不介意。
额外 作者 paul,
我认为值得注意的是,你基本上是在这里创建一个所谓的“结构对象”,因此任何在PHP中进行结构OO的现有工作应该对你有所帮助。
额外 作者 Ptharien's Flame,
我没有时间发表完整的答案,但是如果你需要相互调用的函数,你可以在数组之外定义它们。
额外 作者 Bill Rosmus,
@paul:这个结构的主要目的在上面的$ program代码块中演示 - 我需要能够传递一组键,这将触发许多不同类型的函数。
额外 作者 Wolfie,
@lortabac请注意我上面留给paul的评论,这可能会清楚为什么定义数组外面的函数是不够的
额外 作者 Wolfie,
@paul这听起来像是一个很好的解决方案,但我怎么能实现呢?如何使字符串指向特定函数?
额外 作者 Wolfie,
我的猜测是, $ functions 变量在全局访问后才会被评估并在数组文字中加起来。也许只是声明 $ functions = array(); 并一次添加一个就行了。
额外 作者 Karel Horak,

6 答案

扩展@ lortabac的评论:

您可以通过传递函数名称来传递指向函数的指针,例如:

function fn1()
{
   //...
}

function fn2($fn)
{
    $fn();
}

fn2(fn1);

所以你应该能够像这样填充你的数组:

$functions = [
    "do this" => fn1,
    "do that" => fn2
]

或者,如果您希望能够使用数组中设置的引用使函数能够相互调用,则可以先定义数组,然后编写函数,然后在数组中设置对函数的引用。那。

3
额外

首先,根据DRY原则,您应该尝试使您的功能更加相似,以便他们可以共享尽可能多的代码。这将使管理您的代码库变得非常容易,这不能说是“类似但不同”的功能的数量。

解决问题的可能方法是将所有函数放在一个类中,并在只给出名称的情况下使它们可公开调用。在你的情况下最干净的方法是定义方法 call ,然后使用 __ get 魔术方法调用适当的函数。它非常漂亮且安全(根据实施情况而定)。

1
额外

您基本上是在询问何时以及如何分支机构。我的一般建议是:

  • 仅将代码写入分支一次( DRY )。
  • 调用代码 - 确定代码如何分支,然后再不分支。
  • 考虑使用策略模式命令模式

使用面向对象的方法(根据模式),分支决策可能由 SomethingStrategyManager 类控制,它将为您提供 ISomethingStrategy 的实例。然后你将运行 ISomethingStrategydoTheThing 方法。

在非常通用的伪代码中:

interface IMyStrategy:
  method doTheThing(string name); //returns a BOOLEAN value
  ... //maybe this interface can have more methods?

class MyStrategyManager:
  method getStrategyForSomeArgs(int a, string c) //returns IMyStrategy
     if (a % 2 == 0) return new EvenNumberStrategy();
     else if (a.isPrimeNumber) return new PrimeNumberStrategy();
     else if (c == "CustomSomething") return new CustomStrategy();
     else return new DefaultStrategy();    

...

// Using the strategies:
IMyStrategy strategy = MyStrategyManager.getStrategyForSomeArgs(3, "foo");
BOOL success = strategy.doTheThing("john smith");
... 
1
额外

我认为更好的方法是将数组更改为命名空间。 因此,您可以使用普通函数名称和其他函数的正常调用。

需要时动态调用 - 使用参考。

namespace foo {
  function f1($a) { print "1\n"; };
  function f2($a) { print "2\n"; f1(3); };
}
namespace bar {
  $f = '\foo\f2';
  $f(2);
}
0
额外

您可以创建一个包含所有函数的类,然后将它们作为对象的方法调用

class SimpleFunctions {

  public function doThis() {
   //Do this
  }

  public function doThat() {
   //Do that
  }

  public function doThisInThat() {
   //Do this in That
    $this->doThis();
  }
}

$funcs = ['doThis', 'doThat', 'doThisInThat'];
$simpleFunctions = new SimpleFunctions();
foreach($funcs as $f) {
  if(!method_exists($simpleFunctions, $f))
    throw new \Exception(sprintf("Method %s not found in %s", $f, get_class($simpleFunctions));

  $simpleFunctions->$f();
}
0
额外
程序员正在浏览概念性问题和答案,希望解释事情。抛出代码转储而不是解释就像将代码从IDE复制到白板:它可能看起来很熟悉甚至有时可以理解,但它感觉很奇怪......只是很奇怪。 白板没有编译器
额外 作者 gnat,

我想,在您的FOREACH循环中,您可以添加

$method = '_' . ;

if (method_exists($this, $method)) {
    $this->$method();
}
else {
    show_error('Could not load Method' . $method);
}

算法/逻辑:变量'$ method'将存储函数名和最终可用作方法名的可用键。 IF条件只检查相同方法的可用性,如果方法存在则打开它,否则会抛出错误。

看完整课程将是:

public function your_function()
{
        foreach ($program as $k => $v) {
            //$this->call_function($v);//add 'call_function' in your loop
            $method = '_' . fn.$v; //

            if (method_exists($this, $method)) {
                $this->$method();
            }
            else {
                show_error('Could not load template ' . $method);
            }
        }
}   

public function _fnkey()
{
    echo "In Function 1";
}   

希望这很有用!

0
额外