我正在使用PHP实现OOP设计。我想知道PHP如何处理其__get和__set等神奇方法的继承。
class Foo
{
protected $property1;
public function __get($name)
{
if ($name == "property1")
{
// do some logic
return $result; // may be null
}
return;
}
public function __set($name, $value)
{
if ($name == "property1")
{
// do some logic
return $result; // may be null
}
result;
}
}
现在扩展Foo
:
class Bar extends Foo
{
protected $property2;
public function __get($name)
{
if (($result = parent::__get($name)) !== null)
return $result; // may be null
if ($name == "property2")
{
// do some logic
return $result; // may be null
}
return;
}
public function __set($name, $value)
{
if (($result = parent::__set($name, $value)) !== null)
return $result; // may be null
if ($name == "property2")
{
// do some logic
return $result; // may be null
}
return;
}
}
由于PHP返回null
作为函数的结果而没有返回...这可能会导致parent::__get()
或parent::__set()
真实地返回null或返回no时不明确值;并导致开销。
现在,如果PHP首先考虑static::_get()
和static::__set()
并在失败时回退到parent
版本,则可以简化为:
class Bar extends Foo
{
protected $property2;
public function __get($name)
{
if ($name = "property2")
{
// do some logic
return $result; // may be null
}
return;
}
public function __set($name, $value)
{
if ($name = "property2")
{
// do some logic
return $result; // may be null
}
return;
}
}
我无法在当前实现上对其进行测试,因为上下文中的类操作生产,实时数据库。哪个是正确的实施?
谢谢!
答案 0 :(得分:2)
仅将魔术方法用作代理方法。您的代码将更加清晰,您不必处理由继承引起的问题。
简单示例:
class Foo
{
protected $property1;
public function setProperty1($property1)
{
// do some logic
$this->property1 = $property1;
return $this;
}
public function getProperty1()
{
// do some logic
return $this->property1;
}
public function __get($name)
{
$method = 'get' . ucfirst($name);
if (method_exists($this, $method)) {
return $this->$method();
}
}
public function __set($name, $value)
{
$method = 'set' . ucfirst($name);
if (method_exists($this, $method)) {
$this->$method($value);
}
}
}
class Bar extends Foo
{
protected $property2;
public function setProperty2($property2)
{
// do some logic
$this->property2 = $property2;
return $this;
}
public function getProperty2()
{
// do some logic
return $this->property2;
}
}
示例电话:
$bar = new Bar;
$bar->property1 = 'foo';
$bar->property2 = 'bar';
var_dump($bar);
答案 1 :(得分:1)
我设法创建了一个隔离环境并测试了这两种方法。
方法1
class Foo
{
protected $property1;
public function __get($name)
{
if ($name == "name")
{
echo "been here @line(" . __LINE__ . ") Foo::__get('$name') <br/>";
$result = $this->property1;
return $result; // may be null
}
return;
}
public function __set($name, $value)
{
if ($name == "name")
{
echo "been here @line(" . __LINE__ . ") Foo::__set('$name', '$value') <br/>";
$result = $this->property1 = $value;
return $result; // may be null
}
return;
}
}
class Bar extends Foo
{
protected $property2;
public function __get($name)
{
if ($name == "place")
{
echo "been here @line(" . __LINE__ . ") Bar::__get('$name') <br/>";
$result = $this->property2;
return $result; // may be null
}
return;
}
public function __set($name, $value)
{
if ($name == "place")
{
echo "been here @line(" . __LINE__ . ") Bar::__set('$name', '$value') <br/>";
$result = $this->property2 = $value;
return $result; // may be null
}
return;
}
}
$bar = new Bar;
$bar->name = 'Alice';
$bar->place = 'Wonderland';
echo "done that: '{$bar->name} in {$bar->place}'";
上面的代码结果是:
been here @line(59) Bar::__set('place', 'Wonderland')
been here @line(43) Bar::__get('place')
done that: ' in Wonderland'
这显然不是答案。
方法2
class Foo
{
protected $property1;
public function __get($name)
{
if ($name == "name")
{
echo "been here @line(" . __LINE__ . ") Foo::__get('$name') <br/>";
$result = $this->property1;
return $result; // may be null
}
return;
}
public function __set($name, $value)
{
if ($name == "name")
{
echo "been here @line(" . __LINE__ . ") Foo::__set('$name', '$value') <br/>";
$result = $this->property1 = $value;
return $result; // may be null
}
return;
}
}
class Bar extends Foo
{
protected $property2;
public function __get($name)
{
if (($result = parent::__get($name)) !== null)
{
echo "been here @line(" . __LINE__ . ") parent::__get('$name') <br/>";
return $result; // may be null
}
if ($name == "place")
{
echo "been here @line(" . __LINE__ . ") Bar::__get('$name') <br/>";
$result = $this->property2;
return $result; // may be null
}
return;
}
public function __set($name, $value)
{
if (($result = parent::__set($name, $value)) !== null)
{
echo "been here @line(" . __LINE__ . ") parent::__set('$name', '$value') <br/>";
return $result; // may be null
}
if ($name == "place")
{
echo "been here @line(" . __LINE__ . ") Bar::__set('$name', '$value') <br/>";
$result = $this->property2 = $value;
return $result; // may be null
}
return;
}
}
$bar = new Bar;
$bar->name = 'Alice';
$bar->place = 'Wonderland';
echo "done that: '{$bar->name} in {$bar->place}'";
结果是:
been here @line(22) Foo::__set('name', 'Alice')
been here @line(54) parent::__set('name', 'Alice')
been here @line(59) Bar::__set('place', 'Wonderland')
been here @line(11) Foo::__get('name')
been here @line(38) parent::__get('name')
been here @line(43) Bar::__get('place')
done that: 'Alice in Wonderland'
这是在处理继承时重载__get和__set魔术函数的正确答案,但这会产生开销。这是一个解决方案,但还有更好的解决方案吗?