Возврат нового $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 ​​(). Извините всех за плохие вопросы и спасибо за ответы!

Другие вопросы по тегам