【问题标题】:How to automatically call a method after the __constructor is done in PHP?PHP中__constructor完成后如何自动调用方法?
【发布时间】:2015-11-26 17:06:08
【问题描述】:

我写了一个小的抽象类,叫做Task。我喜欢让每个任务逻辑的类来扩展它。

在我的抽象类“任务”中,我喜欢将每个类中定义的已用定义方法称为“执行”。

我尝试使用魔术方法__call,但它不起作用。

如果您在我的方法中注意到我正在回显一条永远不会在屏幕上打印的消息。

这是我的抽象任务类

<?php

namespace App\Modules\Surveys\Tasks;

use App\Modules\Surveys\Tasks\Support\Traits\HtmlHelper;

abstract class Task
{
    /*
    |
    | This task base class provides a central location to place any logic that
    | is shared across all of your tasks. 
    |
    */

    use HtmlHelper;


    /**
     * checks wether a get method execute exists and calls it
     *
     * @param string $name
     * @param array $args optional
     * @return mixed
     */
    public function __call($name, $args = [])
    {

        echo 'Attempt to execute task';

        if (method_exists($this, 'execute')) {

            return call_user_func_array('execute', $args);

        } else {

            throw new \Exception('execute method does does not exists in your task! ' . get_class($this) );

        }
    }
}


?>

这是一个逻辑类

<?php 

namespace App\Modules\Surveys\Tasks\Interviews;

use App\Modules\Surveys\Tasks\Task;

use App\Modules\Surveys\Models\SurveyInterview;

use Exception;


class ResumeInterview extends Task
{

    protected $surveyId;

    protected $callId;

    protected $myInterview;

    /**
     * Create a new task instance.
     *
     * @return void
     */
    public function __construct($surveyId, $callId)
    {

        $this->surveyId = intval($surveyId);

        $this->callId = intval($callId);
    }


    /**
     * Resume existing interview if one exists using the giving $surveyId and $callId
     *
     * @return void
     */
    protected function execute()
    {
        //find the current interview if one exits
        $myInterview = SurveyInterview::surveyAndCall($this->surveyId, $this->callId)->first();

        $this->setInterview($myInterview);

        if( $this->wasResumed() ){
            //At this point existing interview was found

            if($myInterview->status != 'Pending'){
                //At this point the interview is completed and should not be conducted
                throw new Exception('This interview can not not be retaken. It\'s current status is "' . $myInterview->status . '"');
            }

        }


    }

    /**
     * Return the current interview
     * 
     * @return App\Models\Survey\SurveyInterview
     */
    public function getInterview()
    {
        return $this->myInterview;
    }

    /**
     * It checks whether ot the the interview was resumed
     * 
     * @return boolean
     */
    public function wasResumed()
    {
        return $this->getInterview() ? true : false;
    }

    /**
     * It sets the interview
     * 
     * @param Illuminate\Support\Collection $myInterview
     * @param  void
     */
    protected function setInterview($myInterview)
    {
        $this->myInterview = $myInterview;
    }
}

如果execute方法存在,如何自动调用,否则抛出异常?

【问题讨论】:

  • 为什么不在你的父类构造函数中做这个,然后在子类中做parent::__construct();

标签: php class call magic-methods


【解决方案1】:

我会这样:

abstract class Task {
    [...]

    public function __construct() {
        $this->execute();
    }

    protected function execute() {
        throw new Exception('NOT IMPLEMENTED');
    }

    [...]
}

class ResumeInterview extends Task {
    protected $surveyId;
    protected $callId;
    protected $myInterview;

    public function __construct($surveyId, $callId) {
        $this->surveyId = intval($surveyId);
        $this->callId = intval($callId);
        parent::__construct();
    }

    protected function execute() { [...] }
}

只需在基类构造函数中调用execute()

编辑:请注意,仅当子类实现自己的构造函数时才需要调用parent::__construct();,否则不需要。

【讨论】:

  • 打败我。我会选择这个答案。
  • 那么,如果我也可以在扩展类构造函数中执行 $this->execute(),为什么还需要这段代码呢?我希望避免在每个任务类中编写 $this->execute()
  • 这样你就可以在基类构造函数中添加更多的逻辑并一次性调用它。
  • 所以没有办法避免使用 parent::_construct?
  • @Mike A 验证使用method-exists
【解决方案2】:

为避免在子类中调用parent::__construct,一些框架会定义一个单独的init 方法供子类覆盖,该方法将从父类调用。

abstract class Task
{
    public function __construct($name, $args = [])
    {
        $this->init();
    }
    public function init()
    {
        // Throwing this exception is optional and can be removed to make init optional.
        throw new \Exception('init method must be overridden by child class.');
    }
}

class ResumeInterview extends Task
{
    public function init()
    {
        echo "My awesome init method that does not need to use parent::!";
    }
}

要做到这一点,您根本不能在您的子班级中使用__construct

【讨论】:

  • 我很棒的 init 方法不需要使用 parent:: 做任何事情! 仅当父类实现她自己的 @987654325 @ .. 否则它仍然必须调用 parent::__construct()
  • 最后,这个解决方案和我自己的差不多。
  • @MatteoTassinari 嗯,不,因为它有不同的名称。
  • 哈哈,没错,但总体效果是一样的。
  • @MatteoTassinari 差不多。就我个人而言,我会使用您回答中通常的parent:: 解决方案,只需添加一种替代方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-26
  • 2011-11-12
  • 2021-01-27
相关资源
最近更新 更多