December Code

PHP 8 features interview questions, with answers

PHP 8.0, released in 2020, and the versions since changed the language more than any release in a decade, and interviewers use the new features to find out whether a candidate has kept up. The questions ask what each feature replaces and when to use it, rather than only its syntax.

The answers below cover the match expression, named arguments, constructor promotion, the nullsafe operator, union types, attributes and the JIT compiler, with code run on PHP 8.5. Then take the free PHP diagnostic — ten questions across every PHP topic in the bank — to see which of these you can explain but not yet predict.

The questions, with answers

  1. 1.What is the match expression in PHP 8?

    In short: match compares a value against arms with ===, returns the matching arm's result, never falls through, and throws if nothing matches.

    match is an expression, so its result can be assigned or echoed directly, unlike switch, which is a statement. Each arm lists one or more conditions separated by commas and a single expression. Comparison is strict, there is no fall-through and no break, and when no arm matches and there is no default, match throws an UnhandledMatchError instead of silently doing nothing. Matching on true, as below, turns match into a clean chain of range conditions, the first true arm winning.

    $code = 404;
    echo match (true) {
        $code >= 500 => "server",
        $code >= 400 => "client",
        default => "ok",
    };
    // client
  2. 2.What are named arguments in PHP 8?

    In short: Arguments can be passed by parameter name, in any order, which skips optional parameters and makes calls self-documenting.

    Before PHP 8, to set the fourth parameter of str_pad you had to pass the third as well. With named arguments, str_pad("7", 3, pad_type: STR_PAD_LEFT, pad_string: "0") passes the positional arguments first and then any others by name, in any order. Calls with several boolean or numeric options become readable, and optional parameters in between can be skipped. Named arguments work with built-in and user functions, including constructors, and combine well with constructor promotion to build objects with many options.

    echo str_pad("7", 3,
        pad_type: STR_PAD_LEFT,
        pad_string: "0");
    // 007
  3. 3.What is constructor property promotion in PHP 8?

    In short: A constructor parameter with a visibility modifier declares the property and assigns the argument to it in one step.

    Classes used to repeat every property three times: in the property declaration, in the constructor's parameters and in an assignment in the body. Promotion collapses that: writing public int $w = 0 in the constructor's parameter list declares the property, takes the argument and assigns it. The constructor body can stay empty or hold validation. Promoted parameters can have defaults, types and, since PHP 8.1, the readonly modifier, and combined with named arguments, new Size(h: 5) sets only the parameter it names.

    class Size {
        function __construct(
            public int $w = 0,
            public int $h = 0,
        ) {}
    }
    $s = new Size(h: 5);
    echo "$s->w,$s->h";
    // 0,5
  4. 4.What is the nullsafe operator ?-> in PHP 8?

    In short: $a?->b() calls the method, or reads the property, only when $a is not null; otherwise the whole chain evaluates to null.

    Code that walks through objects that may be missing used to need a null check at every step. With ?->, if the value on the left is null, evaluation of the rest of the chain stops and the expression's result is null, so find(2)?->email() is null when no user is found, while find(1) returns a User whose email is printed. Only the part after the null is skipped: calls to its left still run. The operator reads values but cannot be used on the left of an assignment, and it can be combined with ?? to supply a default for the whole chain.

    class User {
        function email() {
            return "a@b.in";
        }
    }
    function find($id) {
        return $id == 1
            ? new User() : null;
    }
    echo find(1)?->email(), " ";
    var_dump(find(2)?->email());
    // a@b.in NULL
  5. 5.What are union types in PHP 8?

    In short: A type declaration can list several types separated by |, such as int|string, and a value of any of them is accepted.

    Before PHP 8, a parameter that accepted an int or a string had to go untyped and be documented in a comment. Union types, such as int|string, let the declaration say it, and PHP enforces it, throwing a TypeError for anything else. ?T remains shorthand for T|null, and mixed means any value. PHP 8.1 added intersection types, A&B, requiring a value to satisfy several interfaces, and PHP 8.2 allowed combining the two in DNF types such as (A&B)|null. In the code, fmt accepts both an int and a string and reports which it received.

    function fmt(int|string $v) {
        return get_debug_type($v);
    }
    echo fmt(1), " ", fmt("a");
    // int string
  6. 6.What are attributes in PHP 8?

    In short: Attributes, written #[Name(args)], attach structured metadata to classes, methods, properties and parameters, readable through Reflection.

    Frameworks used to put configuration in docblock comments, such as @Route("/home"), which PHP itself treated as text. Attributes are native syntax for the same purpose: #[Route("/home")] attaches a Route attribute to a class, and the attribute is an ordinary class marked with #[Attribute]. Nothing happens automatically; code reads attributes through the Reflection API, as below, and newInstance creates the attribute object with its arguments. Symfony routes, Doctrine mappings and validation rules are all expressed this way, and PHP itself uses attributes such as #[Override] and #[Deprecated].

    #[Attribute]
    class Route {
        function __construct(
            public string $path,
        ) {}
    }
    
    #[Route("/home")]
    class Home {}
    
    $c = "Home";
    $r = new ReflectionClass($c);
    $a = $r->getAttributes()[0];
    echo $a->newInstance()->path;
    // /home
  7. 7.What is the JIT compiler in PHP 8, and does it speed up web applications?

    In short: The JIT compiles hot PHP code to machine code at run time; it helps CPU-heavy work a lot but typical web requests, which wait on I/O, much less.

    PHP normally compiles scripts to opcodes, which OPcache stores and the Zend engine interprets. The JIT, added in PHP 8.0 as part of OPcache, goes a step further and compiles frequently executed code paths to native machine code while the program runs. For CPU-bound work, such as image processing or mathematical computation, that can bring large speedups. Typical web applications spend most of their time waiting on databases, caches and the network, so the JIT improves them only modestly; OPcache itself remains the most important performance setting for them. The JIT is configured with opcache.jit and opcache.jit_buffer_size.

How the diagnostic asks it

One question from the PHP bank, exactly as a sitting would show it. The bank has 4 on modern php and 30 across PHP.

Modern PHP · easyPHP-024

What does this PHP 8 code print?

$v = "1";
echo match ($v) {
    1 => "int",
    "1" => "string",
    default => "other",
};
  1. 1int
  2. 2stringcorrect
  3. 3other
  4. 4int, then string

match, added in PHP 8, is an expression that compares its subject with each arm using strict comparison, ===, and returns the value of the first arm that matches. The string "1" is not identical to the integer 1, so the first arm is skipped and the second, "1", matches: string. int is what switch would print, since switch compares loosely with ==. other would need no arm to match. match never falls through to later arms, and if no arm matches and there is no default, it throws an UnhandledMatchError.

Measure it

Reading answers tells you what’s true. A diagnostic tells you what you get wrong.

10 PHP questions across its topics, easy to hard, about fifteen minutes. You get a readiness figure with the arithmetic shown, the topics you missed named, and a practice set sized for today. Free: 1 diagnostic a month and 15 problems a day. No card.

What the readiness test measures · how the score is computed

By Harshit · updated