New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
Typing a dependency injection container #4310
Comments
I found these snippets: https://psalm.dev/r/f4113ff8b9<?php
class A {
public function foo(): void {}
}
/**
* @template T
* @param class-string<T>|string $name
* @return T|mixed
*/
function f(string $name) {
/** @var T $obj */
$obj = "fixme";
return $obj;
}
$a = f(A::class);
$a->foo();
$b = f('hello');
https://psalm.dev/r/b86ac518bd<?php
class A {
public function foo(): void {}
}
/**
* @template T
* @param class-string<T> $name
* @return T
*/
function f(string $name) {
/** @var T $obj */
$obj = "fixme";
return $obj;
}
$a = f(A::class);
$a->foo();
|
Looks like conditional types( https://psalm.dev/docs/annotating_code/type_syntax/conditional_types/ ) should help here, but I'm not sure how to correctly tell psalm to allow just string as param https://psalm.dev/r/fb3073f1f0 Upd: but it works well if pass an argument as a variable https://psalm.dev/r/6cee64fd5e |
I found these snippets: https://psalm.dev/r/fb3073f1f0<?php
/**
* @template T
* @param string|class-string<T> $name
* @return (T is object ? T : mixed)
*/
function get(string $name) {
return;
}
get('abc');
https://psalm.dev/r/6cee64fd5e<?php
/**
* @template T
* @param string|class-string<T> $name
* @return (T is object ? T : mixed)
*/
function get(string $name) {
return;
}
/** @var string $str */
get($str);
/** @var class-string $class */
get($class);
|
Thanks a lot for the tip with the conditional types! I learned something new today :)
Indeed it works with variables but problems show as soon as literals are used: https://psalm.dev/r/5008a6ddb5. |
I found these snippets: https://psalm.dev/r/6cee64fd5e<?php
/**
* @template T
* @param string|class-string<T> $name
* @return (T is object ? T : mixed)
*/
function get(string $name) {
return;
}
/** @var string $str */
get($str);
/** @var class-string $class */
get($class);
https://psalm.dev/r/5008a6ddb5<?php
/**
* @template T
* @param string|class-string<T> $name
* @return (T is object ? T : mixed)
*/
function get(string $name) {
return;
}
/** @var string $str */
get($str);
get('name');
/** @var class-string $class */
get($class);
|
This seem to work better: |
I found these snippets: https://psalm.dev/r/b4cdb6c683<?php
class name{}
/**
* @param string|class-string $name
* @return ($name is class-string ? object : mixed)
*/
function get(string $name) {
return;
}
$str = 'a';
/** @var class-string $class */
$class = 'b';
/** @psalm-trace $a */
$a = get($str);
/** @psalm-trace $b */
$b = get('name');
/** @psalm-trace $c */
$c = get(name::class);
/** @psalm-trace $d */
$d = get($class);
|
Thanks for looking into it but then there is no type information on the returned object. Psalm will treat it as But with this new hint of |
I found these snippets: https://psalm.dev/r/30724e7f25<?php
class A {
public function foo(): void {}
}
/**
* @template T
* @param string|class-string<T> $name
* @return ($name is class-string ? T : mixed)
*/
function get(string $name) {
return;
}
$str = 'a';
/** @var class-string $class */
$class = 'b';
/** @psalm-trace $a */
/** @var string $a */
$a = get($str);
/** @psalm-trace $b */
$b = get(A::class);
$b->foo();
/** @psalm-trace $c */
$c = get('Literal');
/** @psalm-trace $d */
$d = get($class);
|
@muglug you're amazing. Thanks a lot for the quick fix 馃檶. |
You're welcome! |
Hello 馃憢,
I'm in the process of rolling out Psalm for more components of the Nextcloud ecosystem and I came to the following problem. If you have a dependency injection container, it would be really cool to let Psalm know the container returns an instance of the class string passed as identifier, though containers might also work with regular strings as service identifications.
Sample code: https://psalm.dev/r/f4113ff8b9
If I limit the container interface to only work with class strings, then the typing is easy: https://psalm.dev/r/b86ac518bd. But in practice you have some named services where the string is not actually a class string but just a literal.
Does Psalm automatically use the class string as more specific type? It looks like the union type with
string
has no effect except eliminating the errorArgument 1 of f expects class-string, parent type string(...) provided
. Therefore it still complains about every service that is queried by name instead of class name likeClass or interface hello does not exist
in the example above..Unfortunately I could not find any other container implementation that uses psalm typing.
Are there any tricks to make this work?
What I'm trying to tell Psalm is
T
is returnedmixed
in any other caseThe text was updated successfully, but these errors were encountered: