Reputation: 11990
I wrote a small abstract class that is called Task. I like to have every task logic's class to extend it.
Within my abstract class "Task" I like to call a used defined method "execute" that is defined in every class.
I tried to use the magic method __call
but it is not working.
If you notice in my method I am echoing a message which never prints on the screen.
Here is my abstract Task class
<?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) );
}
}
}
?>
Here is a logical class
<?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;
}
}
How would I automatically call the execute method if it exists, otherwise throw an exception?
Upvotes: 3
Views: 2582
Reputation: 60507
To avoid having to call parent::__construct
in the sub-classes, some frameworks will define a separate init
method for the child to override, which will be called from the parent.
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::!";
}
}
To do this you would have to not use __construct
in your child class at all.
Upvotes: 0
Reputation: 18584
I would go like this:
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() { [...] }
}
simply call execute()
in the base class constructor.
EDIT: notice that the call to parent::__construct();
is only needed if the child class implements her own constructor, else it is not required.
Upvotes: 5