Возврат нового $this с абстрактными классами
Я нашел некоторые проблемы с моим кодом и не понимаю, почему он делает так, как есть. Кто-нибудь может мне объяснить?
Пусть у нас есть:
abstract class AbstractThing
{
public function search(...)
{
$ret = false;
$data = $database->query(...);
foreach($data as $values)
{
$item = new $this;
$item->fill_with_values($values);
$ret []= $item;
}
return $ret;
}
}
Он работает как задумано и возвращает экземпляры объекта при успешном поиске:
class Thing extends AbstractThing
{
// ...
}
$thing = new Thing;
$things = $thing->search(...); // Thing[] on success, false on failure
Но если я хочу немного укоротить код, он ломается:
abstract class AbstractThing
{
public function search(...)
{
$ret = false;
$data = $database->query(...);
foreach($data as $values) {
$ret []= (new $this)->fill_with_values($values);
}
return $ret;
}
}
Это возвращение логическое истина. Зачем? Это хорошо работает на классах, которые не унаследованы от абстрактного класса.
3 ответа
Когда мы назначаем:
$ret []= (new $this)->fill_with_values($values);
... мы не сидим $ret[] = (new $this)
, Вместо этого этот оператор выдвигает возвращаемое значение fill_with_values()
в массив, потому что он выполняется последним.
Похоже, вы пытаетесь реализовать нечто похожее на шаблон фабричного метода. Учти это:
abstract class AbstractThing
{
...
public static function fill($values)
{
$instance = new static;
$instance->fill_with_values($values);
return $instance;
}
}
Тогда мы действительно можем сделать то, что вы пытаетесь достичь в вашем вопросе, вот так:
$ret[] = static::fill($values);
Это работает, потому что возвращаемое значение fill()
является экземпляром класса, а не возвращаемым значением fill_with_values()
, static
Ключевое слово в этом контексте использует позднюю статическую привязку для определения типа класса, который выполняет код (Thing
в данном случае) вместо класса, который его объявляет, поэтому он работает через наследование. Смотрите этот вопрос для получения дополнительной информации.
Код делает 2 разные вещи:
Это добавляет $item к вашему массиву "ret":
$item = new $this;
$item->fill_with_values($values);
$ret []= $item;
Это добавляет возвращенное значение "fill_with_values" в ваш массив:
$ret []= (new $this)->fill_with_values($values);
Эквивалентом приведенного выше кода будет:
$item = new $this;
$return = $item->fill_with_values($values);
$ret []= $return;
Если бы я знал, что происходит в вашем методе "fill_with_values", я мог бы сказать вам, почему это логическое значение, но код не делает то же самое. Надеюсь, что это имеет смысл.
Хорошо, наконец, это была моя собственная ошибка. В какой-то момент была действительно возможность вернуть TRUE из функции fill_with_values (). Извините всех за плохие вопросы и спасибо за ответы!