答案 0 :(得分:4)
通常,当您与第三方API通信或方法/成员结构不清楚时,这些方法很有用。
假设您正在编写一个通用的XML-RPC包装器。由于在下载WDL文件之前您不知道可用的方法,因此使用重载是有意义的。
然后,而不是写下以下内容:
$xmlrpc->call_method('DoSomething', array($arg1, $arg2));
您可以使用:
$xmlrpc->DoSomething($arg1, $arg2);
这是一种更自然的语法。
您也可以像对变量对象的方法重载一样使用成员重载。
您只想注意一件事:将其仅限于变量结构对象,或仅将其用于getter和setter的语法快捷方式。保持类中的getter和setter在多种方法中分离业务逻辑是有意义的,但将它用作快捷方式没有错:
class ShortcutDemo {
function &__get($name) {
// Usually you want to make sure the method
// exists using method_exists, but for sake
// of simplicity of this demo, I will omit
// that logic.
return call_user_method('get'.$name, $this);
}
function __set($name, &$value) {
return call_user_method('set'.$name, $this, $value);
}
private $_Name;
function &getName() { return $this->_Name; }
function setName(&$value) { $this->_Name = $value; }
}
通过这种方式,您可以继续使用getter和setter来验证和设置数据,并仍然使用语法快捷方式:
$shortcut->Name = 'Hello';
答案 1 :(得分:0)
安德鲁没有提到的另一种方法(或在撰写本文时尚未提及)是为了摆脱吸气剂和制定者。而不是像这样声明每个setter和getter:
$obj->setName("Chacha");
$obj->setRep(10000000000000000000000);
你可以改为
$obj->Name = "chacha";
$obj->Rep = 100000000000000000;
第二种方法更自然。
Magic Methods基本上是对面向对象编程的思考,以及你如何实现工作的想法对外界来说无关紧要。通过Magic Methods,它允许您根据需要存储变量,并让其他类以自然的方式设置它们。
示例:我可以将所有用户的帐户首选项存储在一个数组中,这样可以非常轻松地进行迭代,将其全部推送到会话中。
如果我没有使用Magic方法,我要么必须制作一堆或者获取,这意味着要编写更多代码,或者允许直接访问数组,这会显示实现,所以我可以以后再去改变它。
相反,使用魔术方法,我只是让他们定期设置变量,我在内部处理它。
答案 2 :(得分:0)
您可以将它用于类具有isset和unset的复杂规则的情况。例如,包含变量$ a的类可以是对象或其他资源的数组,并且在未设置时,它们必须执行一些其他功能。
虽然我不确定为什么他们允许添加新属性并检索非私有属性,但您可以使用它来通过调用其他代码来更改对象的内部状态,具体取决于属性的名称/成员变量被设置。
在某些情况下,这类似于C ++中的运算符重载
答案 3 :(得分:0)
当您具有多态性不是一个选项的组合或聚合对象时(例如,您使用的是无法控制的库类)的消息转发。
<?php
// Class A is final, so we can't make subclasses.
final class A
{
public function hello( $callback )
{
echo call_user_func( $callback, 'hello world' );
}
}
// so instead, we make a wrapper class that will take an instance
// of A as an aggregate
class B
{
private $a;
public function __construct( A $a )
{
$this->a = $a;
}
// this mimics inheritance on the aggregate object
// method calls are automatically forwarded to instance of A
// if they are valid
public function __call( $method, $args )
{
if ( method_exists( $this->a, $method ) )
{
return call_user_func_array( array( $this->a, $method ), $args );
}
throw new Exception( "Method [$method] not found." );
}
}
class C extends B
{
// This mimics overriding an "inherited" method
public function hello( $callback )
{
echo call_user_func( $callback, 'bonjour le monde' );
}
}
$a = new A;
$b = new B( $a );
$c = new C( $a );
$b->hello( 'strtoupper' );
$c->hello( 'strtoupper' );
答案 4 :(得分:0)
这个功能实际上是what object oriented programming is all about,在其发明者Alan Kay的脑海中:对象发送对方的消息,并可能对任何类型的消息作出反应。在编译时修复的方法是这个概念的有限(但也更有效)的实现。这就是凯的着名引用“我发明了面向对象这个术语的地方,我可以告诉你,C ++并不是我想到的。”来自。
基本上,允许对象在没有在编译时修复相应方法的情况下对方法调用作出反应,实现了这个原始的,更广泛的面向对象定义。大多数现代“动态”语言都以某种形式支持它。
至于它有什么好处:看看Groovy's Builders是一个很好的例子。基本上,它通过将方法名称本身转换为数据,允许非常紧凑的低冗余语法。
答案 5 :(得分:0)
我使用它的一种方式,相当有点发烧,就是创建一个像对象关系管理(ORM)系统一样的Linq。然后,您可以在其中加载数据库表结构并操纵数据(从数据库表中),就像它只是一个对象一样。
即
include('blibrary/bLinq.class.inc');
$linq = new bLinq(new bLinqSql('mysql://dsn'));
$r = $linq->from('Users')
->password
->select();
转换为以下SQL:
SELECT `password` from Users;
select语句中的password
来自重载方法。
结果可以像:
一样使用(array)$r->password; // which outputs an array multiple results of password;
(string)$r->password; // which outputs a string of the first password hash;
$r->password[2]; // which outputs a string of the third password hash;
关键是在编程时,“password
”这个词可以代替数据库中的任何其他字段。
答案 6 :(得分:0)
我使用__get和__set将对象链接在一起,例如
$user = new User();
echo $user->Profile->views;
这(通常)调用一些SQL链接users.id = profile.user_id。
答案 7 :(得分:0)
属性(如Python或C#中的属性)。例如,当您使用类似in Nette的内容时,您创建了一些类,它将某些属性显示为public:
<?php
class Foo extends Object
{
public $bar;
}
您可以自然地访问此媒体资源 - $instance->bar
。但是当你想做一些验证等时,你只需要添加getter和setter:
<?php
class Foo extends Object
{
private $bar;
public function getBar()
{
return $this->bar;
}
public function setBar($bar)
{
if ($bar === NULL) throw new Exception('…');
$this->bar = $bar;
}
}
仍然使用$instance->bar
。但是,当您执行$instance->bar = NULL;
时,就像调用$instance->setBar(NULL);
。