How to indicate in php 7.1 that the return type is the current child type?

1.4k Views Asked by At

I have

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 has no type hinting... I like type hinting, so I want type hinting for B, not for A

How to enable type hinting directly for $x?

what I thought is something like

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

This obviously doesn't work

Is there something that does?

4

There are 4 best solutions below

5
bijiDango On BEST ANSWER

For the example you present, why do you need to have a factory method? You are creating a new instance from the constructor, why don't you just $x = new B($record)!

UPDATED ABOVE


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 will type hinting its child class. Also I changed your function to static function, it is typical factory pattern.

4
Dmitry On

Add @method B getSingle to the B class phpdoc.

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

}

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

1
Bell On

Let the abstract class implement an interface and type hint that interface. The child does not have to implement the interface explicitly.

abstract class A implements BarInterface
  {
    public function foo (): BarInterface
      {    
        return new static;
      }
  }
0
yivi On

I know that you specify PHP 7.1, but starting with PHP 8 (to be released on November 2020) this will be possible with the addition of the static return type hint.

The RFC was approved unanimously, 54-0.

This means you'll be able to do:

class Foo

   public static function build(): static
   {
        return new static();
   }
}

class Bar extends Foo {}

Additionally, no need to muck around with $classname = get_called_class(); new $classname();. You can simply do new static(), which is neater and has the same result.

And Bar::build() is type-hinted to indicate that it returns Bar and not Foo by virtue of late static binding.