PHP OO重试逻辑实现并传递动态方法和args

时间:2009-06-10 09:07:47

标签: php

我的第一个问题。

问题与此类似:PHP: Retrying a query a set number of times or until success

尝试以OO方式取得成功。 这里是我想要做的例子:

class Creatives {

    public function run() {
        $auth_token='mypassword';
        $id=123123;
        $this->retry_till_success ( $this->getCreatives, array($auth_token, $id) );
        print $this->creatives; 
    }

    public function getCreatives($auth_token, $id) {
        $this->creatives = $this->campagin->get($auth_token, $id);      
    }

    private function retry_till_success($method, $args) {
        do {
            $try_again = false;
            try {
                /* how to call the method with */
                /* call user method with params pass */
                /* do until success */
            } catch (SoapFault $fault) {
                if($fault->faultstring== 'couldnt connect to host')
                    $try_again=true;
            }
        } while ($try_again);
    }
}

我读过call_user_func,但不知道我是否可以在课堂内使用它, 我需要在我的通话中取得99.9%的成功率,任何实现这一目标的建议都会很棒。 谢谢。

6 个答案:

答案 0 :(得分:2)

最好的方法是扩展SoapClient并在__call方法中添加重试。

class LocalSoapClient extends SoapClient
{

  public function __call($function_name, $arguments)
  {
    $result = false;
    $max_retries = 5;
    $retry_count = 0;

    while(! $result && $retry_count < $max_retries)
    {
      try
      {
        $result = parent::__call($function_name, $arguments);
      }
      catch(SoapFault $fault)
      {
        if($fault->faultstring != 'Could not connect to host')
        {
          throw $fault;
        }
      }
      sleep(1);
      $retry_count ++;
    }
    if($retry_count == $max_retries)
    {
      throw new SoapFault('Could not connect to host after 5 attempts');
    }
    return $result;
  }
}

然后当您实例化您的soap客户端时,请使用new LocalSoapClient()而不是new SoapClient()

答案 1 :(得分:1)

call_user_func_array()非常适合:

$result = call_user_func_array( array($this, $method), $args );

第一个参数是回调pseudo-type,第二个参数是一个参数数组,它们将作为单独的参数传递给函数/方法。

作为旁注,您可能希望查看限制重试(例如,每次失败达到设定限制时,睡眠时间会加倍)。如果与主机的连接断开,那么尽可能快地重试可能没什么意义。

答案 2 :(得分:0)

private function retry_till_success($method, $args) {

...

$this->$method($args[0], $args[1]);

}

你也可以使用ReflectionClass / ReflectionMethod并调用InvokeArgs()来获取可变数量的args

http://nz.php.net/oop5.reflection

答案 3 :(得分:0)

我不太清楚你的意思,但这就是call_user_func(_array)()的工作原理:

call_user_func($method, $arg); //call global function named $method like this: $method($arg)
call_user_func(array($this, $method), $arg); call class method on this class like this: $this->$method($arg);
//lets presume args is an array: $args = array(1, 2);
call_user_func_array($method, $args); //calls global function named $method like this: $method($args[0], $args[1]);
call_user_func_array(array($this, $method), $args); //calls class method like this: $this->$method($args[0], $args[1]);

另请参阅call_user_func的文档:
http://nl3.php.net/manual/en/function.call-user-func.php
并且对于call_user_func_array:
http://nl3.php.net/manual/en/function.call-user-func-array.php

答案 4 :(得分:0)

$this->getCreatives将无法正常工作,因为PHP函数不是基类公民。您可以使用call_user_func[_array]或为任务创建工厂,并将每个任务表示为实现接口的对象(即iRepeatableTask)。因此你可以打电话

try
{    
    $task->repeatUntilSuccess()
} catch (SoapFault $e) {...}

并且优点是这些目标在DB中易于保存/恢复以便稍后执行(即使用cronjob等)。

答案 5 :(得分:0)

这是我在制作中使用的最终解决方案。

    protected function retry_till_success($method, $args) {
    /*
    *   -1 : unrecoverable error
    *    0 : recoverable error
    *    1 : success
    */
    $success = 0;
    $tries = 0;

    do {
        $tries++;
        $success = call_user_func_array( array($this, $method), $args );
        if ($success===0) {
            usleep(self::DELAY_MS);
        }
    } while ($success===0 && $tries < self::MAX_RETRIES);

    if ($tries >= self::MAX_RETRIES)
        return false;

    return true;
}