在PHP中重载属性和方法-原因是什么?


Overloading properties and methods in PHP - what's the reason?

仅仅因为可爱的函数命名原因而使用重载是一个好主意吗?:)

例如:

echo $store->product->getPrice($currency);

  • product将调用__get,然后调用__getObject('product'),它执行神奇的事情并返回当前被视为对象的产品(如果它是第一次调用,则将其实例化)

echo $store->product('dog')->getPrice($currency);

  • 这里product将调用__call,然后调用__callObject('product',…)…


没有重载的替代方法是:

if(!$store->product)
  $store->product = new Product();
 echo $store->product->getPrice($currency);

$product = new Product('dog');
echo $product->getPrice($currency);

我非常喜欢重载,因为我可以为我的类获得很好的API。但是缺点是重载的东西比直接调用属性/方法要慢15倍。

像这样使用重载是可以的吗?

在我当前的应用程序中,我没有调用重载成员超过1000次。这应该不会对性能产生太大影响。也许额外的0.1秒,考虑到一个站点通常在0.5 - 1s内生成,这并不是那么多

仅仅因为可爱的函数命名原因而使用重载是一个好主意吗?:)

。我是说,这要看情况。:)让我们为我们的编程生活添加一些令人敬畏和可爱的东西:

$ordinary = new stdClass();
$ordinary->Caption = 'Hello';
class Awesome
{
   private $ordinary;
   public function __construct($ordinary) {
       $this->ordinary = (array) $ordinary;
   }
   public function __get($name) {
       $value = '';
       return $this->ordinary[$name];
   }
}
class Lovely extends Awesome
{
    public function __get($name)
    {
        return '<3 ' . parent::__get($name) . ' <3';
    }
}

我必须承认,这个例子可能有点夸张,但它显示了一些东西。

首先,假设API是针对类的。所以它从一个非常普通的stdClass开始。

这个例子表明,这些神奇的函数可以用来重载修饰。可以,但不可以。看看这个很棒的API,它本身就很棒:
$awesome = new Awesome($ordinary);
echo $awesome->Caption, "'n"; # This caption is just awesome by itself!
# Hello

然后看看更可爱的API示例:

$lovely = new Lovely($ordinary);
echo $lovely->Caption, "'n"; # This caption is lovely, hughs and kisses everyone!
# <3 Hello <3

所以在这个例子中,对于Lovely来说这是个好主意但是对于Awesome来说就没用了,因为Awesome实际上更容易获得:

$awesome = $ordinary;

这让我想到了一点,API中的重载只能在特定的点上有用。正如Lovely所示,它可以用来装饰另一个(没有太多指定的对象),但它也表明这只是一次性的:Lovely已经需要知道如何调用Awesome来使用它的功能(现在不再神奇了)__get方法:

    public function __get($name)
    {
        return '<3 ' . parent::__get($name) . ' <3';
    }

当你现在认为Awesome是你的API时,你可以看到它阻止了自己被其他想要使用它的代码重载。

所以重载在具体代码中是可以的,API不应该阻止它。但是当API本身重载时,事情就变得很困难了。

不仅对于编码,添加动态/魔法也会使调试变得困难。因此,最好对您创建的api保持清晰,并提供比[]->更具体的接口。你可以给事物起具体的名字,这很有效;)

和它比起来更可爱:

echo $store->getObject('product')->getPrice($currency);

重载的缺点是,您必须自己描述"漂亮的API",因为文档工具无法理解您在方法中做了什么。另一点是,它通常是"太多的魔法":你实现的魔法越多,你的代码就越难以理解。

另一方面,我认为你的替代方案没有任何问题。在我眼里它甚至更干净。

旁注:避免在方法的开头使用双下划线,只要你没有实现魔法方法。

坚持面向对象的设计原则带来了好处。第一个示例通过从工厂生成产品对象来实现松耦合。有关OO设计原则的更多信息,请参见S.O.L.I.D.和G.R.A.S.P.