原型模式
原型设计模式允许我们有效地复制对象,同时将重新实例化对象对性能的影响降至最低。
如果你使用过 JavaScript,你可能听说过原型语言。在这种语言中,您可以通过克隆原型对象来创建新对象;反过来,创建新对象的成本也会降低。
到目前为止,我们已经广泛讨论了 __construct
方法的使用,但还没有涉及 __clone
魔法方法。__clone
魔法方法是在克隆对象(如果可能的话)之前运行的方法;该方法不能直接调用,也不需要参数。
在使用这种设计模式时,你可能会发现使用 __clone
方法很有用;尽管如此,根据你的使用情况,你可能并不需要它。
重要的是要记住,当我们克隆一个对象时,__construct
函数不会重新运行。对象已经被构造出来了,所以 PHP 认为没有理由再重新运行它,因此在使用这种设计模式时应该避免在这里放置有意义的逻辑。
让我们首先定义一个基本的 Student
类:
Unresolved include directive in modules/ROOT/pages/ch03/ch3-07.adoc - include::example$/Chapter 3/Prototype/Student.php[]
现在让我们开始构建我们的 index.php
文件,首先包含我们的 Student.php
类文件:
require_once('Student.php');
然后我们可以创建此类的实例,设置各种变量,然后 var_dump
对象的内容,以便我们可以调试对象内部的详细信息以查看它是如何工作的:
Unresolved include directive in modules/ROOT/pages/ch03/ch3-07.adoc - include::example$/Chapter 3/Prototype/index.php[]
该脚本的输出如下所示:

到目前为止,一切顺利;我们基本上声明了一个基本类,并设置了各种属性。下一个挑战是克隆这个脚本。我们可以在 index.php
文件中添加以下几行:
Unresolved include directive in modules/ROOT/pages/ch03/ch3-07.adoc - include::example$/Chapter 3/Prototype/index.php[]
这看起来像什么?看看吧

这看起来很简单;我们已经克隆了一个对象并成功更改了该对象的属性。我们最初的对象,原型,现在已经通过克隆它来构建一个新的学生而投入使用。
是的,我们可以再次这样做,如下所示:
Unresolved include directive in modules/ROOT/pages/ch03/ch3-07.adoc - include::example$/Chapter 3/Prototype/index.php[]
但我们还可以做得更好;通过使用匿名函数(也称为闭包),我们实际上可以动态地向该对象添加额外的方法。
让我们为我们的对象定义一个匿名函数:
Unresolved include directive in modules/ROOT/pages/ch03/ch3-07.adoc - include::example$/Chapter 3/Prototype/index.php[]
最后,让我们回显新克隆对象的 var_dump
,同时也执行我们刚刚创建的 dance
函数:
Unresolved include directive in modules/ROOT/pages/ch03/ch3-07.adoc - include::example$/Chapter 3/Prototype/index.php[]
您会注意到,事实上,我们必须使用 __invoke
魔术方法来调用匿名函数。 当脚本尝试将对象作为函数调用时,将调用此方法;在类变量中调用匿名函数时,这一点至关重要。
这是因为 PHP 类属性和方法都位于不同的命名空间中; 为了执行类变量中的闭包,您需要使用 __invoke;
首先,将其分配给类变量,使用 call_user_func
或使用 __call
魔术方法。
在这种情况下,我们只使用 __invoke
方法。
因此,脚本的输出如下所示:

注意到我们的函数在最底部运行了吗?
完整的 index.php
文件如下所示:
Unresolved include directive in modules/ROOT/pages/ch03/ch3-07.adoc - include::example$/Chapter 3/Prototype/index.php[]
有一些很好的用例;假设您想要执行交易。您可以获取一个对象,克隆它,如果所有查询都成功,则替换原始对象,并将克隆的对象提交到数据库以代替原始对象。
这是一种非常有用且轻量级的克隆对象的方法,您知道克隆的对象需要与其父对象相同或几乎相同的内容。