【问题标题】:Conditionally chain a method?有条件地链接一个方法?
【发布时间】:2016-11-29 02:52:11
【问题描述】:

我们如何在 PHP 中有条件地链接方法?例如,这很好用:

$a->foo()->bar->baz->qux();

但是,根据条件,我想链接一些方法而不是其他方法。基本上,缩短以下代码:

if ($cond === true) {
    $a->foo()->baz();
} else {
    $a->foo()->bar();
}

理想情况下,如下所示:

$a->foo()
    ->bar()
    ($cond === true) ? ->baz() : ->qux()
    ->more();

此外,我们如何根据条件有条件地链接(或不链接)方法?例如:

$a->foo()
    ->bar()
    if($cond === true) ->baz()
    ->more();

【问题讨论】:

  • 不需要像那样模糊你的代码。除了幼稚的“看起来很酷”之外,短符号的好处是 0 。如果您想学习,请成为比这更好的程序员。
  • @Weltschmerz 在我的特殊情况下,这不是看起来很酷的问题,但如果不做这样的事情,我根本不知道如何使用这个类。因此,这更多是缺乏知识和/或提出错误问题的问题。下次我会问一个更具体的问题。

标签: php oop


【解决方案1】:

通过将链接分配给变量来试试这个

$a = $a->foo();

if ($cond === true) {
   $a = $a->baz();
} else {
   $a = $a->bar();
}

$a->more();

【讨论】:

  • 最简单的答案
【解决方案2】:

下面的不言自明的模拟片段(您可以在此处Quick-Test)展示了如何做到这一点

<?php   

    class Test{
        protected $prop1;
        protected $prop2;
        protected $prop3;
        protected $prop4;

        public function __construct() {
        }

        public function setProp1($prop1) {
            $this->prop1 = $prop1;
            return $this;
        }

        public function setProp2($prop2) {
            $this->prop2 = $prop2;
            return $this;
        }

        public function setProp3($prop3) {
            $this->prop3 = $prop3;
            return $this;
        }

        public function setProp4($prop4) {
            $this->prop3 = $prop4;
            return $this;
        }
    }

    $a      = 2;
    $b      = 7;
    $cond   = ($a > $b);
    $cond2  = ($b > 50);
    $test   = new Test;

    $test->setProp1(2)->{($cond  === true)  ? 'setProp4' : 'setProp3'}(11);
    $test->setProp3(3)->{($cond2 === false) ? 'setProp2' : 'setProp4'}(6);

    var_dump($test);
    //YIELDS::
    object(Test)[1]
      protected 'prop1' => int 2
      protected 'prop2' => int 6
      protected 'prop3' => int 3
      protected 'prop4' => null

【讨论】:

    【解决方案3】:

    你正在寻找的是variable methods (see example #2). 他们允许你做这样的事情:

    class a {
        function foo() { echo '1'; return $this; }
        function bar() { echo '2'; return $this; }
        function baz() { echo '3'; return $this; }
    }
    $a = new a();
    
    $cond = true;
    $a->foo()->{($cond === true) ? 'baz' : 'bar'}();
    // Prints 13
    $cond = false;
    $a->foo()->{($cond === true) ? 'baz' : 'bar'}();
    // Prints 12
    

    这是一种让您为每个函数调用设置要求的方法。请注意,这与以前的解决方案一样难以维护,如果不是更难的话。您可能还想使用某种配置和ReflectionClass's getMethods function

    class a {
        function foo() { echo '1'; return $this; }
        function bar() { echo '2'; return $this; }
        function baz() { echo '3'; return $this; }
    }
    
    function evaluateFunctionRequirements($object, $functionRequirements, $condition) {
      foreach ($functionRequirements as $function=>$requirements) {
        foreach ($requirements as $requiredVariableName=>$requiredValue) {
          if (${$requiredVariableName} !== $requiredValue) {
            continue 2;
          }
        }
        $object->{$function}();
      }
    }
    
    $a = new a();
    $functionRequirements = array('foo'=>array(), 'bar'=>array(), 'baz'=>array('condition'=>true));
    $condition = true;
    evaluateFunctionRequirements($a, $functionRequirements, $condition);
    // Prints 123
    $condition = false;
    evaluateFunctionRequirements($a, $functionRequirements, $condition);
    // Prints 12
    

    注意:这增加了 更难维护 需要函数才能为 $functionRequirements 数组。此外,这个基本示例只传递了一个可能的条件变量,更新到另一个设置以获得更多具有func_get_args 的 $requiredVariableName 变量。您还需要验证通过 $functionRequirements 传入的方法是 is_callable() 安全的。

    【讨论】:

    • 我想指出,这在未来不是很容易维护。假设您需要重构任何方法名称等。
    • 我认为没有更好的方法,否则他将不得不求助于 eval(不推荐)
    • @KevinStich 谢谢,这很接近!此外,我更新了问题以仅包括在满足条件时链接特定方法,否则不包括。这实际上是我今天的具体用例:)
    • @LookingToLearn 确保在你不知道你住在哪里之后维护此代码的人。
    • @zerkms 哈!我认为它是可维护的,至少是我现在写的形式。我错误地问了这个问题,所以稍微澄清一下(最后)。
    【解决方案4】:

    解决此问题的另一种方法是创建一个方法when(或命名任何对您有意义的名称):

        public function when($condition, $callback)
        {
            if ($condition) {
                return $callback($this) ?: $this;
            }
            return $this;
        }
    

    当然,如果你需要将它们传递给你的方法foobar等,你可以扩展它来接受额外的参数......

    链接的用法是:

    $a->when($cond === true, function ($a) {
        return $a->foo();
    })->when($cond !== true, function ($a) {
        return $a->bar();
    }
    )->baz(); // a regular chaining method without condition
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-25
      • 1970-01-01
      • 2011-12-09
      • 2020-07-03
      • 2017-02-23
      • 1970-01-01
      • 2019-11-02
      相关资源
      最近更新 更多