LostMekkaSoft
LostMekkaSoft

Reputation: 363

PHP dynamic return type hinting

Suppose I have the following PHP function:

/**
 * @param string $className
 * @param array $parameters
 * @return mixed
 */
function getFirstObject($className, $parameters) {
    // This uses a Doctrine DQl builder, but it could easily replaced
    // by something else. The point is, that this function can return
    // instances of many different classes, that do not necessarily
    // have common signatures.
    $builder = createQueryBuilder()
        ->select('obj')
        ->from($className, 'obj');
    addParamClausesToBuilder($builder, $parameters, 'obj');
    $objects = $builder
        ->getQuery()
        ->getResult();
    return empty($objects) ? null : array_pop($objects);
}

Basically, the function always returns either an instance of the class specified with the $className parameter or null, if something went wrong. The only catch is, that I do not know the full list of classes this function can return. (at compile time)

Is it possible to get type hinting for the return type of this kind of function?

In Java, I would simply use generics to imply the return type:

static <T> T getOneObject(Class<? extends T> clazz, ParameterStorage parameters) {
    ...
}

I am aware of the manual type hinting, like

/** @var Foo $foo */
$foo = getOneObject('Foo', $params);

but I would like to have a solution that does not require this boilerplate line.

To elaborate: I am trying to write a wrapper around Doctrine, so that I can easily get the model entities that I want, while encapsulating all the specific usage of the ORM system. I am using PhpStorm.

** edited function to reflect my intended usage. I originally wanted to keep it clean of any specific use case to not bloat the question. Also note, that the actual wrapper is more complex, since I also incorporate model-specific implicit object relations and joins ect.

Upvotes: 4

Views: 5110

Answers (3)

Ahsaan Yousuf
Ahsaan Yousuf

Reputation: 725

If you use PHPStorm or VSCode (with the extension PHP Intelephense by Ben Mewburn) there is an implementation named metadata where you could specify your own type-hinting based on your code doing the magic inside. So the following should work (as it did on VSCode 1.71.2)

<?php
namespace PHPSTORM_META {    
    override(\getFirstObject(0), map(['' => '$0']));
}

Upvotes: 1

Nuryagdy Mustapayev
Nuryagdy Mustapayev

Reputation: 785

I use phpdoc @method for this purpose. For example, I create AbstractRepository class which is extend by other Repository classes. Suppose we have AbstractRepository::process(array $results) method whose return type changes according to the class that extends it. So in sub class:

/**
* @method Car[] process(array $results)
*/
class CarRepo extends AbstractRepository {
    //implementation of process() is in the parent class
}

Update 1:

You could also use phpstan/phpstan library. Which is used for static code analyses and you can use it to define generic return types:

/**
 * @template T
 * @param class-string<T> $className
 * @param int $id
 * @return T|null
 */
function findEntity(string $className, int $id)
{
    // ...
}

Upvotes: 2

allanlaal
allanlaal

Reputation: 237

This can now be achieved with the IntellJ (IDEA/phpStorm/webStorm) plugin DynamicReturnTypePlugin: https://github.com/pbyrne84/DynamicReturnTypePlugin

Upvotes: 0

Related Questions