I would like to do self::container()->get($path);
but self::container()
can return null
.
Is there a quicker way to avoid the Call to a member function get() on null
error when chaining function calls and some could return null instead of an object ?
Is there a better way than the ugly workaround of mocking the expected object/member?
public static function getDependency($path) {
return self::container() ??
(new class{public function get($path){return null;}})->get($path);
}
What I am after is something like the null-conditional member access operator (?.
) in C#
As of PHP 8.0, you have Nullsafe methods and properties and you can do:
self::container()?->get($path);
Otherwise, you have the original answer below as it targeted PHP 7.3:
Short answer: no, there is no such thing in PHP 7.3.
I would avoid doing magic like the one you suggested.
Doing:
<?php
public static function getDependency($path) {
$container = self::container();
if ($container instanceof ContainerInterface) {
return $container->get($path);
}
}
would be easier to read/understand.
Now, regarding null
, it has been described by its own creator (Tony Hoare) "The Billion Dollar Mistake".
A better approach would be that self::container()
would have as return type ContainerInterface
without the possibility of being null
. Trying to returning a null
, it would throw a TypeError
, which could potentially be caught. This way, the call to ->get()
would never happen as the exception would be thrown before.
Allowing self::container()
to return something like ContainerInterface|null
would result in all callers to implement a logic as the one you proposed which would also lead to (lot of) duplicated code.
For the very same reason, you would probably be safer to have a specific return type for your dependency:
<?php
public static function getServiceFoo($path): ServicFoo {
$container = self::container();
if (!$container instanceof ContainerInterface) {
throw new RuntimeException("Not a valid container received");
}
return $container->get($path);
}
Otherwise you will be exposed to the same issue on getServiceFoo()
that you already have on self::container()
.