как указать в php 7.1, что возвращаемый тип является текущим дочерним типом?


У меня есть

abstract class A{
  public static function getSingle($where = []) {
    $classname = get_called_class();

    $record =     static::turnTheWhereIntoArecordFromDB($where);
    $model = new  $classname($record);
    return $model;
  }
}

class B extends A{

}


$x = B::getSingle();

$x не имеет никакого намека на тип... Мне нравится намек на тип, поэтому я хочу, чтобы намек на тип был для B, а не для A

Как включить прямое указание типа для $x?

Я подумал что-то вроде

 public function getSingle($where = []) : ?get_called_class()

Очевидно, что это не работает

Есть ли что-то, что делает?

РЕДАКТИРОВАТЬ в соответствии с запросом на комментарий: я добавил фрагменты, которые, по моему мнению, отсутствовали в исходном вопросе выше.

Более полный исходный код см. Ниже. Не стесняйтесь комментировать, но на самом деле это не является частью вопроса. Мои сомнения в отношении приведенного ниже кода в большей степени связаны с интерфейсом использования. Например, $where является ['my_column_name' => 'my_column_val'], что приводит к my_column_name = 'my_column_val' и, в конечном итоге, к последствиям для безопасности. Но, это действительно плохой ORM для программистов.

protected abstract static function get_tablename();

  /**
   * @param array $where
   * @return static|null
   */
  public static function getSingle($where = []) {
    /** @var wpdb $wpdb */
    global $wpdb;
    $qr     = static::whereToString($where);
    $sql    = "SELECT *  FROM " .$wpdb->prefix . static::get_tablename() . " WHERE ". $qr ;
    $record = $wpdb->get_row($sql);

    if(!$record){
      return null;
    }

    $classname = get_called_class();

    $model = new  $classname($record);
    return $model;
  }

  /**
   * @param array $where
   * @return string
   */
  private static function whereToString(array $where): string
  {
    $i   = 0;
    $max = sizeof($where);
    $qr  = '';
    foreach ($where as $name => $val) {
      if (is_string($val)) {
        $qr .= " {$name} = '" . $val . "' ";

      } else {
        $qr .= " {$name} = " . $val . " ";
      }

      $i++;
      if ($i < $max) {
        $qr .= ' AND ';
      }
    }
    return $qr;
  }
Author: Toskan, 2017-09-22

3 answers

Для приведенного вами примера, зачем вам нужен заводской метод? Вы создаете новый экземпляр из конструктора, почему бы вам просто $x = new B($record)!

ОБНОВЛЕНО ВЫШЕ


abstract class A
{
    /**
     * @param array $where
     * @return static
     */
    public static function getSingle($where = [])
    {
        $classname = get_called_class();

        $model = new  $classname($record);
        return $model;
    }
}

@return static будет вводить намек на свой дочерний класс. Также я изменил вашу функцию на статическую функцию, это типичный заводской шаблон.

 3
Author: bijiDango, 2017-09-22 16:42:23

Добавьте @method B getSingle в B класс phpdoc.

/**
* Class B
* @method B getSingle
*/
class B extends A{

}

Https://docs.phpdoc.org/references/phpdoc/tags/method.html

 1
Author: Dmitry, 2017-09-22 16:14:50

Позвольте абстрактному классу реализовать интерфейс и введите подсказку об этом интерфейсе. Ребенку не нужно явно реализовывать интерфейс.

abstract class A implements BarInterface
  {
    public function foo (): BarInterface
      {    
        return new static;
      }
  }
 0
Author: Bell, 2017-09-22 20:41:53