方法链和类继承

5

我认为我已经基本掌握了面向对象编程(OOP)/继承以及方法链的基础知识。然而,我仍然困惑于如何实际运用其中的一些内容。

我想做的事情是我之前在使用Magento时看到的一些操作: 在Magento中,我看到一种称为“选择器函数”的方法链被使用。很难用语言描述,但大致上是这样的:

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

我对load($categoryId)这部分很感兴趣,因为它是选择某个实例并允许我在该特定实例上运行函数的功能。

现在,我正在编写一个模块,使我能够在我们的网站上配置某些促销活动。由于我们将有许多不同的促销活动,并且我希望它们易于配置和修改,所以我想做类似的事情。

因此,如果我想要像这样做:

$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!

那个类的定义应该是什么样子的?

这可能比我预料的要简单或者复杂得多。无论哪种情况,非常感谢!


编辑: 所以,我根据deceze给我的信息进行了一些测试,但我仍然感到困惑。 除了糟糕的命名和在一个文件中放置两个类之外,这是我做的:

类文件:

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!


可能是PHP方法链接?的重复问题。 - kapa
这被称为流畅接口 - 因此方法将返回自身实例。在某种意义上,它是一种反模式。 - Alma Do
1
实际上我看到的问题是,你应该从getPromo方法中返回PROMO实例,像这样:return $this->__arr[$name]; - code-jaff
Deceze 比你快了一两分钟。当然,你是绝对正确的,我只是太糊涂了,没看到我忘了它。 :) - Flosi
2个回答

1

方法链接非常简单,它只是使用PHP语法的一个特定元素:

当函数返回一个对象时,您可以直接在该函数后继续使用 ->

长版本可以是:

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

$foo->bar() 返回一个对象 ($bar),该对象有一个方法 baz(),并且该方法返回一些值 ($baz)。这可以简写为:

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

$foo->bar() 仍然返回一个对象,该对象具有一个方法 baz(),因此您可以直接调用它,而无需将其分配给中间变量。也许这样更明显:

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

你正在对 $foo->bar() 返回的结果调用 baz() 方法。
$prm->getPromo('xmasPromo')->setName('Promotion for Xmas!');

因此,在您上述的情况下,您所需要做的就是从getPromo返回一个具有setName方法的对象。我会假设getPromo应该返回某个类(比如Promo类)的对象。如果Promo类有一个setName方法,那么您就可以了。

嗨,感谢您的回答。拥有“Promotion”类和“Promo”类(具有setName和getName方法)很容易。但是,“Promotion”类中如何创建或获取适当的“Promo”对象实例以进行addPromo和getPromo函数呢? - Flosi
1
我不知道,这取决于你。当你调用 addPromo 方法时,Promotion 类会创建一个新的 Promo 对象(命名不太好),并将其与给定的名称存储在内部某个位置。当你调用 getPromo 方法时,它会检索该对象。可以是简单的数组,也可以是复杂的数据库查询。你需要自己决定实际上想要进行什么操作。 - deceze
我感谢你的帮助。我尝试使用数组,但似乎仍然无法掌握它。请参见原始帖子。 - Flosi
1
可能是因为你没有使用 return 返回值! - deceze
啊,我怎么会这么糊涂。还忘了在 getName 中加上 $this。现在可以工作了。这回答了我的问题,真的帮助我理解了这个概念。非常感谢! - Flosi

1
如果您想链接方法,只需像这样始终返回对象即可。
class Chain {
    public function firstChain() {
         //do something
         return $this;
    }

    public function secondChain() {
          //do some stuff

          return $this;
    }

}

当你拥有该类的一个实例时,你需要这样做:
$obj = new Chain();

$obj->fistChain()->secondChain();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接