как указать в 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;
}
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
будет вводить намек на свой дочерний класс. Также я изменил вашу функцию на статическую функцию, это типичный заводской шаблон.
Добавьте @method B getSingle
в B
класс phpdoc.
/**
* Class B
* @method B getSingle
*/
class B extends A{
}
Позвольте абстрактному классу реализовать интерфейс и введите подсказку об этом интерфейсе. Ребенку не нужно явно реализовывать интерфейс.
abstract class A implements BarInterface
{
public function foo (): BarInterface
{
return new static;
}
}