PHP 8.1 : `never` return type
24, April 2021

Prepare for death, ye who enter here.

Nope, this is not a threat. this is just explanation of newly introduced never return type in PHP 8.1


Umm, what?

Calm down. Let's try to demonstrate what problem we can solve with this never return type.

Say, in our app, we have a method that only throws a exception, does not return anything of sort. It just prepares proper exception and throws it.

But why would we create a method just to throw exception? - Sometime, you should. Proper self-explained exception message can be very much helpful during debugging. And to prepare well-formatted message, you might need to do some processing that deserve a dedicated method.

<?php

class SomeClass
{
  function ensureUserHasPermission(User $user, Action $action): void
  {
      if($user->hasPermission($action) === false){
          userHasNoPermission($user, $action);
      }
  }
  
  function userHasNoPermission(User $user, Action $action)
  {
     if(config('environment') === 'production'){
        /*
        * here we can have some logic related to production
        * maybe some extensive logging for later debug 
        */
     }

     /*
     * here we can have some logic related to dev/testing
     * maybe some dev friendly message, eg. how to allow permission
     */
  }
}

Above, we have method ensureUserHasPermission() who just check if user has the proper permission for the action. If hasPermission() returns false, that means user does not have permission, in that case, it calls userHasNoPermission(). You may have notice, we do not want to continue our app when user does not have permission, so userHasNoPermission() should be the last thing to be executed. We may throw some exception here, we may even call die()/exit()

Now, let me ask you a question, "What return type should userHasNoPermission() method have?". You may think of void return type, but void just means that the function returns nothing. void does not mean that method stops PHP process by exception/die/exit call.

Actually, PHP does not have any proper return type to define this behavior, until now.


Yep, that method should have never return type.

function userHasNoPermission(User $user, Action $action): never
{
    // die or exit
}

never means, once we call this method, PHP process will be stopped by it. So no code will be processed after this method call.

echo 'a';
methodThatHasNeverReturnType(); // php will be stopped here
echo 'b'; // this line will not execute


Another example is, when we have a method that redirect to url.

function redirectToLogin(): never
{
    header('location: https://site.com/login');
    exit;
}

This method just redirect and then exit. This method should have never return type.


If a method has never return type, can we return something from it?

No, you can't. method containing never return type can't return anything.

function foo(): never
{
    return 'something'; // will throw TypeError

    return; // will not work either.
}


What if I do not stop PHP process inside never method?

never-declared method must throw exception or call die/exit. If not, PHP will throw TypeError

function foo(): never
{
   echo "something";
}

foo(); // Uncaught TypeError: foo(): never-returning function must not implicitly return


never can only be used as return type

We can't use never as property/parameter type. we can't use it in union type either. never must be defined in function return type only.


When extending a class:

class Foo
{
    function redirect(): never{}
}

class FooBar extends Foo
{
    function redirect(): string{}
}
// Declaration of FooBar::redirect(): string must be compatible with Foo::redirect(): never

//however, we can change other return type to never
class Foo
{
    function redirect(): string{}
}

class FooBar extends Foo
{
    function redirect(): never{}
}
// this is allowed



As you can see, even though use cases for never return type is limited, this new addition to PHP type system is still quite handy.