oop — перегрузка PHP __set и __get при наследовании

Я реализую дизайн ООП с использованием PHP. Интересно, как 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 верно или вернулся без значения; и приводит к накладным расходам.

Теперь, если 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;
}
}

Я не могу проверить это на текущей реализации, потому что классы в контексте манипулируют производственной базой данных. Какая правильная реализация?

Спасибо!

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);
2

Другие решения

Мне удалось создать изолированную среду и протестировать оба метода.

Способ 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 при работе с наследованием, но это накладные расходы. Это решение, но есть ли лучшее решение?

1

По вопросам рекламы [email protected]