PHP魔法方法的实际应用——__get、__set和__call
我通常会尝试远离 PHP 的魔术方法,因为它们似乎混淆了对象的公共接口。也就是说,它们似乎被越来越多地使用,至少在我读过的代码中,所以我不得不问:对于何时使用它们有任何共识吗?这三种魔法的使用有什么共同的模式吗?
I've generally tried to stay away from PHP's magic methods because they seem to obfuscate an object's public interface. That said, they seem to be used more and more, at least, in the code I've read, so I have to ask: is there any consensus on when to use them? Are there any common patterns for using these three magic methods?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
主要原因是您不需要输入太多内容。例如,您可以将它们用于 ORM 记录并充当隐式设置器/获取器:
using
__call()
:using
__set()
:映射到一个简单数组:
将这样的数组写入数据库比进行大量手动调用来收集所有需要的信息要容易得多。与公共成员相比,
__set()
和__get()
还具有另一个优势:您可以验证/格式化您的数据。The main reason is that you do not need to type as much. You could use them for, say, an ORM record and act as implicit setters/getters:
using
__call()
:using
__set()
:which maps to a simple array:
It is much easier to write such an array to the database than doing a lot of manual calls to collect all needed information.
__set()
and__get()
have another advantage over public members: You are able to validate/format your data.__call()
我见过它用于实现行为,例如通过可插件接口向类添加额外的函数。
像这样的伪代码:
它还使得编写大部分相似的函数变得更容易,例如在 ORM 中。例如:
__get()/__set()
我主要看到它用于包装对私有变量的访问。
ORM 是我想到的最好的例子:
__call()
I've seen it used to implement behaviors, as in add extra functions to a class through a pluginable interface.
Pseudo-code like so:
It also makes it easier to write mostly similar functions, such as in ORMs. e.g.:
__get()/__set()
I've mostly seen it used to wrap access to private variables.
ORMs are the best example that comes to mind:
它允许您执行以下操作:
然后您可以在一行中从 SQL 查询填充
$propertybag
,而不是逐个设置一大堆属性。此外,它还允许您拥有只读的特定属性(即不允许通过
__set()
修改它们)。例如,对于 ID 字段可能很有用。此外,您还可以将代码放入
__get()
和__set()
中,这样您就可以做一些比仅获取或设置单个变量更复杂的事情。例如,如果您有一个storeID
字段,您可能还需要提供一个storeName
属性。您可以通过交叉引用查找在 __get() 中实现该功能,因此您可能不需要将名称实际存储在类中。当然,storeName
不希望在__get()
中实现。那里有很多可能性。
当然,使用魔法方法也有一些缺点。对我来说最大的问题是你失去了 IDE 中的自动完成功能。这对您来说可能重要,也可能不重要。
It allows you to do things like this:
Then you can populate
$propertybag
from a SQL query in a single line, rather than setting a whole bunch of properties one by one.Also, it allows you to have specific properties which are read-only (ie don't allow them to be modified via
__set()
). Maybe useful for an ID field, for example.Also, you can put code into
__get()
and__set()
, so you can do something more complex than just getting or setting a single variable. For example, if you have astoreID
field, you may also want to provide astoreName
property. You could implement that in__get()
via a cross-reference lookup, so you may not need the name actually to be stored in the class. And of coursestoreName
would not want to be implemented in__get()
.Lots of possibilities there.
There are of course some down-sides of using magic methods. The biggest one for me is the fact that you lose the auto-complete functionality in your IDE. This may or may not matter to you.
由于当涉及到定义成员、填充它们然后检索它们等重复性任务时,魔术方法可以为您节省大量编码 - 您可以使用上述 3 种方法来缩短编码时间,而不是做那些无聊而漫长的工作所有这些。如果需要,我可以提供一些示例,它们可以在网上的各种教程中找到。
我不知道这是否是普遍共识,但通常应该适用 - 在适当的地方使用。如果您发现自己正在执行重复性任务(定义成员、填充成员、获取成员、调用略有不同的 X 函数) - 魔术方法可能会帮助您。
Since magic methods can save you a LOT of coding when it comes to repetitive tasks like defining members, populating them and then retrieving them - instead of doing that boring, long piece of work, you can use mentioned 3 methods to shorten the time to code all that. If needed, I can provide a few examples tho they can be found in various tutorials over the net.
I don't know if it's general consensus, but the usual should apply - use where appropriate. If you find yourself to do repetitive task (define member, populate member, get member, call X functions that differ slightly) - magic methods might help you.
一种常见的模式是为您的客户端提供一个句柄,并根据命名约定或配置代理对封装对象或单例的调用。
可以使用相同的原理来驱动相同功能的不同后端,而无需更改驱动程序。
One common pattern is to have a single handle for your clients and proxy the calls to encapsulated objects or singletons based on naming conventions or configurations.
Same principles can be used to drive different backends of the same functionality without having to change the driver.
只要您愿意,只要记录了魔法属性/方法即可;除非使用非常抽象的代码层(例如开发 ORM 时),否则应避免使用未记录的魔法。
在抽象层可接受
记录后可接受
惰性且不可接受(在使用 ORM 时很常见)
Whenever you'd like, as long as the magic properties/methods are documented; undocumented magic should be avoided unless working with a very abstract layer of code, such as when developing an ORM.
acceptable at an abstract layer
acceptable when documented
lazy and unacceptable (and common when using ORMs)
作为使用示例,类
Request
可以读取 $_REQUEST 或 _GET、$_POST 并提供根据某些需要或为了舒适而修改或清理的字段值。它可以使用 __get 为任何字段提供值或 null,从而消除繁琐的 if(isset($_REQUEST['afield'])) 检查,并且它可以使用 __call 提供相同但接受一些参数,例如默认值,如果字段未定义。
** 代码是作为示例编写的,因此未经测试 **
As a sample of usage, a class,
Request
can read $_REQUEST or _GET, $_POST and provide field values modified or cleaned according to some necessities or for confort.It can use __get to provide value or null for any field, eliminating the tedoius if(isset($_REQUEST['afield'])) checks, and it can use __call to provide the same but accepting some parameter such as a default value, if field is undefined.
** CODE IS WRITTEN HERE AS A SAMPLE, SO IT IS UNTESTED **