我正在查看Doctrine 2和Symfony文档来创建模型类。有几个代码片段在类中使用了getProperty和setProperty,当将值直接分配给属性时,这些代码片段会以某种方式自动使用。这与典型的get/set魔术方法不同,并且我遇到的示例代码没有实现任何自定义魔术方法,所以我相信这是由Doctrine在某个地方处理的。
据我所知,Doctrine实现了访问器和mutator。也许我在下载Pear时漏掉了一个包,或者我的脚本中没有包含某些内容。
例如:class User {
public $name;
public function getName()
{
// Do stuff
}
}
$user = new User();
$foo = $user->name; // getName is called
注意:我正在寻找一个教条特定的解决方案。我知道这可以用PHP以某种方式完成,但我想使用Doctrine的本地函数。
编辑:更新以澄清这与典型的get/set魔术方法的区别,并注意。
class User {
private $name;
public function __get($property) {
$methodName = "get".ucfirst($property);
if (method_exists($this, $methodName)) {
return call_user_func(array($this, $methodName));
} elseif (isset($this->{$property})) {
return $this->{$property};
}
return null;
}
public function __set($property, $value) {
$methodName = "set".ucfirst($property);
if (method_exists($this, $methodName)) {
call_user_func_array(array($this,$methodName), array($value));
} else {
$this->{$property} = $value;
}
}
public function getName() {
return "My name is ".$this->name;
}
}
$user = new User();
$user->name = "Foo";
$bar = $user->name;
echo $bar; // "My name is Foo"
如果有方法getSomething
或setSomething
,它将在直接访问属性时被调用。
正如我在这个文档页面中读到的,上面的代码所做的正是Doctrine所做的。但是它调用了_set('fieldName', 'value')
方法
如果$name
被声明为public
,那么这行代码:
$foo = $user->name;
实际上是访问$name
字段,而不是调用getName
函数。
你可以使用PHP神奇的__get
和__set
方法来自动提供访问器和变量,像这样:
class User {
private $name;
public function __get($property) {
//check first to make sure that $property exists
return $this->$property;
}
public function __set($property, $value) {
//check first to make sure that $property exists
$this->$property = $value;
}
}
$user = new User();
$user->name = "Foo";
$bar = $user->name;
echo $bar; //"Foo"
你可以在这里找到更多关于PHP魔法方法的信息。
UPDATE:这就是我认为Doctrine正在做的事情:
class User {
private $name;
public function __get($property) {
$propertyTitleCase = mb_convert_case($property, MB_CASE_TITLE);
$method = "get{$propertyTitleCase}";
if(method_exists($this, $method))
{
return $this->$method();
}
else {
return $this->$property;
}
}
public function getName() {
//Do Stuff
}
}