Reputation: 363
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
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
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
Reputation: 237
This can now be achieved with the IntellJ (IDEA/phpStorm/webStorm) plugin DynamicReturnTypePlugin: https://github.com/pbyrne84/DynamicReturnTypePlugin
Upvotes: 0