2

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#

beppe9000
  • 1,036
  • 1
  • 13
  • 27

2 Answers2

2

With the upcoming PHP 8 the nullsafe_operator will be implemented and will allow to circuit break a chain of calls if null is returned by one of them

   $result = $o->returnNull()?->doSomething()
   $results === null // True
Maks3w
  • 5,549
  • 6
  • 35
  • 41
1

This answer applies for PHP versions olders than 8.0.0. For PHP 8.0.0 and later see Maks3w answer

Short answer: no, there is no such thing in PHP.

I would avoid, at all price, 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().

Maks3w
  • 5,549
  • 6
  • 35
  • 41
Patrick Allaert
  • 1,683
  • 17
  • 43