Pergunta

I think I have more or less managed to get a grasp on OOP/Inheritance, and the basics of method chaining I think I understood as well. However I am still confused about how to actually use some of it.

I wanted to do something that I've seen when working with Magento before: In Magento, I've seen some sort of "selector-function" used in method chaining. It's a little hard to put into words, but it was something along the lines of:

$categoryName = Mage::getModel('catalog/category')->load($categoryId)->getName();

It's the load($categoryId) part that interests me, as in, a function that selects some instance of something and allows me to run a function on that specific instance.

Now, I am writing a module that allows me to configure certain promotions on our website. Seeing as we'll have many different promotions and I want them to be easily configurable and modifiable, I wanted to do something similar.

So, if I wanted to be able to do something like this:

$prm = new Promotion();

$prm->addPromo('xmasPromo');
$prm->addPromo('nyPromo');

$prm->getPromo('xmasPromo')->setName('Promotion for Xmas!');
$prm->getPromo('nyPromo')->setName('Promotion for New Years!');

echo $prm->getPromo('xmasPromo')->getName(); // returns: Promotion for Xmas!
echo $prm->getPromo('nyPromo')->getName(); // returns: Promotion for New Years!

How would the class definition for that have to look like?

This may be much more simple or much more complicated than I anticipate. In either case, thanks a lot!


Edit: So I did some testing around with the info deceze gave me, but I'm still confused. Bad naming and putting 2 classes in 1 file aside, here's what I did:

class file:

class Promotion {
    private $__arr = array();
    public function addPromo($name) {
        $this->__arr[$name] = new Promo();
    }
    public function getPromo($name) {
        $this->__arr[$name];
    }
}

class Promo {
    private $name;
    public function setName($name) {
        $this->name = $name;
    }
    public function getName() {
        return $name;
    }
}

and the run file:

require_once 'class.php';
error_reporting(E_ALL);

$prm = new Promotion();

$prm->addPromo('xmasPromo');
$prm->addPromo('nyPromo');

$prm->getPromo('xmasPromo')->setName('Promotion for Xmas!');
$prm->getPromo('nyPromo')->setName('Promotion for New Years!');

echo 'X: '.$prm->getPromo('xmasPromo')->getName(); // returns: Promotion for Xmas!
echo "\n";
echo 'N: '.$prm->getPromo('nyPromo')->getName(); // returns: Promotion for New Years!

This gives me Fatal error: Call to a member function setName() on a non-object in /var/www/test/index.php on line 11. But why? Shouldn't getPromo() give me back the object? Thanks again..


Thanks to the great guys here, it works now. In case anyone were to pass by here with the same or a similar question, here's the final, working code:

Classes:

class Promotion {
    private $__arr = array();
    public function addPromo($name) {
        $this->__arr[$name] = new Promo();
    }
    public function getPromo($name) {
        return $this->__arr[$name];
    }
}

class Promo {
    private $name;
    public function setName($name) {
        $this->name = $name;
    }
    public function getName() {
        return $this->name;
    }
}

Test file:

require_once 'class.php';
error_reporting(E_ALL);

$prm = new Promotion();

$prm->addPromo('xmasPromo');
$prm->addPromo('nyPromo');

$prm->getPromo('xmasPromo')->setName('Promotion for Xmas!');
$prm->getPromo('nyPromo')->setName('Promotion for New Years!');

echo 'X: '.$prm->getPromo('xmasPromo')->getName(); // returns: Promotion for Xmas!
echo "\n";
echo 'N: '.$prm->getPromo('nyPromo')->getName(); // returns: Promotion for New Years!
Foi útil?

Solução

Method chaining is really simple, all it does is use one particular element of PHP's syntax:

When a function returns an object, you can directly continue with -> after that function.

The longhand version can be:

$bar = $foo->bar();
$baz = $bar->baz();
echo $baz;

$foo->bar() returns an object ($bar) which has a method baz(), and that method returns some value ($baz). This can be written in shorthand like so:

echo $foo->bar()->baz();

$foo->bar() still returns an object which has a method baz(), so you can directly call it without assigning it to an intermediate variable. Maybe this makes it more obvious:

echo ( $foo->bar() )->baz();

You're calling the baz() method on whatever $foo->bar() returns.

$prm->getPromo('xmasPromo')->setName('Promotion for Xmas!');

As such, in your above case, all you need to do is to return an object which has the method setName from getPromo. I would assume getPromo is supposed to return some object of, say, the Promo class. If the Promo class has a method setName, you're all set.

Outras dicas

If you want to chain methods you just need to always return the object like this

class Chain {
    public function firstChain() {
         //do something
         return $this;
    }

    public function secondChain() {
          //do some stuff

          return $this;
    }

}

Than when you have an instance of the class you do like this:

$obj = new Chain();

$obj->fistChain()->secondChain();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top