views:

103

answers:

5

I'm currently doing it this way,but seems not the proper way:

class Name
{
    protected $jobs2do;

    public function __construct($string) {
        $this->jobs2do[] = $this->do;
    }

        public function do() {
        ...
    }
}

Because directly assign a function will cause warning,should do something like:

function func() { ... }

$func_array[] = 'func';

say,put it into a string,but I don't know how to do it when it's a member function?

Is the following version OK?:

class Name
{
    public $jobs2do;

    public function __construct($string) {
        $this->jobs2do[] = array($this,'do');
    }

        public function do() {
        ...
    }
}

when call it,just :

$instance = new Name();
foreach ($instance->jobs2do as $job)
        {
         call_user_func($job);
        }
A: 

Take a look at the callable pseudo type. You can then call that function with call_user_func():

class Foo {
    function bar($str) {
        echo($str);
    }
}

$foo = new Foo();
$func_array = array();
$func_array['foo->bar'] = array($foo, 'bar');  // this is the 'callable' pseudo-type

call_user_func($func_array['foo->bar'], "Hello World");



Edit: It seems you're trying to implement the command pattern. In that case you could try something along these lines:

// define an interface for all actions
interface Executable {
    public function do();
}

// an example action
class DoSomething implements Executable {
    private $name;

    public __construct($name) {
        $this->name = $name;
    }

    public function do($str) {
        echo("Hello $str, my name is $this->name");
    }
}

$objects_to_process = array(new DoSomething("Foo"), new DoSomething("Bar"));
foreach ($objects_to_process as $obj) {
    if ($obj instanceof Executable)
        $obj->do("World");
}
n3rd
But I'm not going to call user function,but a member function:(
Shore
Doesn't matter. Just look at my little example.
n3rd
Thank you,I've updated my post,could you tell me if that's right when in a constructor?
Shore
I've updated my post as well ;)
n3rd
Oh,seems you are using multiple instances,which is different from my design:(
Shore
Okay, I see. Fair enough. Yes, I think your code looks fine then.
n3rd
A: 

Please check call_user_func() or call_user_func_array()

Ropstah
A: 

Write a class for Job and use factory pattern to create them. Then Write a class JobManager wihich should maintain a list ob Job instances.

interface iCallableJob
{
    public function run();
}

class Job implements iCallableJob
{
    // The parameterized factory method
    public static function factory($type)
    {
     $classname = 'Job_' . $type;
     if (class_exists($classname) && in_array('iCallableJob', class_implements('Job')))
     {
      return new $classname();
     }
     return null;
    }
    public function run() { return null; }
}

class Job_type1 extends Job 
{
    public function run() 
    {
     echo 'Job 1';
    }
}

class JobManager
{
    protected $jobs2do = array();

    public function addJob($type)
    {
     if ($job = Job::factory($type))
     {
      $this->jobs2do[] = $job;
      return $job;
     }
     return null;
    }
    public function runAll()
    {
     foreach ($this->jobs2do AS $job)
     {
      $job->run();
     }
    }
}
Jet
A: 

There can be several possible solutions to this problem. You have Command and Factory patterns presented in other replies. This one illustrates how to use Visitor + Command pattern cooperation.

class Name {

    protected $jobs = array();

    public function addJob(IJob $j) {
        $this->jobs[] = $j;
    }

    public function do() {
        foreach ($this->jobs as $j) {
            $j->run($this);
        }
    }

}

interface IJob {

    public function run(Name $invoker);

}

class WashDishes implements IJob {

    public function run(Name $invoker) {
        echo get_class($invoker) . ' washes dishes<br/>';
    }

}

class DoShopping implements IJob {

    public function run(Name $invoker) {
        echo get_class($invoker) . ' does shopping<br/>';
    }

}

$n = new Name();
$n->addJob(new WashDishes());
$n->addJob(new DoShopping());
$n->do();

Output:

Name washes dishes
Name does shopping

A class implementing IJob interface is a command that can be passed and stored for later execution. The way Name object invokes jobs in collection (passing $this reference) is typical for Visitor pattern (this way job object has access its caller - Name object). However, true Visitor pattern is not possible in PHP due to lack of native support for explicit method overriding.

Michał Rudnicki
A: 

There are (at least) 4 ways to do this. There are other ways but these are the most pure. The method versions require PHP5 at a minimum.

class foo {
    public function bar($a) { return $a; }
}

$anObject = new foo();
$ret = call_user_func(array($anObject,'bar'), 1);
$ret = call_user_func_array(array($anObject,'bar'), array(1));
$ret = call_user_method('bar', $anObject, array(1));
$ret = call_user_method_array('bar', $anObjectm, 1);

You can replace 'bar' with a string variable, too.

jmucchiello