34
votes

I just felt on pieces of php (symfony/laravel) code using question mark in method type hints :

public function functionName(?int $arg = 0)

In other occasions the ?type was not the last one, but I did not find any of these with no default yet.

Problem is, I cannot find any information about this, and I checked :

And same with 7.2, but since the code only requires 7.1, it seems rather normal.

I also googled, and searched here, but either this is not documented or the question marks topic is defeating search engines.

So I feel a little dumb now, and I would really appreciate if someone could enlighten me on the significance of this question mark in method signatures arguments.

Thanks

3
You're right lol. The worst thing is I knew about the meaning as return value. Thanks for the enlightenmentfab2s

3 Answers

36
votes

It's a new feature in php7.1

http://php.net/manual/en/migration71.new-features.php

A question mark means that the type hinted parameter (or return value) is also allowed to be null.

So in your example $arg can be null or any integer.

9
votes

Just a note to add to the previous answers - it must be either null or have a value in the specified type i.e. - you cannot just omit it - have a look at an example:

class TestClass {

    public function fetch(?array $extensions)
    {
        //...
    }        
}

Now if you call

(new TestClass)->fetch();

this will throw

ArgumentCountError : Too few arguments to function fetch() ...

To make it work without passing array of $extensions you'd have to call it with null as argument

(new TestClass)->fetch(null);

It works best in the situations, where you are passing argument initially set to null to another method for processing i.e.

class TestClass {

    public function fetch(array $extensions = null)
    {
        //...

        $this->filter($extensions);
    }

    private function filter(?array $extensions)
    {
        //...
    }
}

Now you can call the fetch method without the argument

(new TestClass)->fetch();
2
votes

Consider the following functions:

<?php

function testFnc1(string $param)
{
    var_dump($param);
}

function testFnc2(string $param = 'some string')
{
    var_dump($param);
}
    
function testFnc3(string $param = null)
{
    var_dump($param);
}

function testFnc4(?string $param)
{
    var_dump($param);
}

function testFnc5(?string $param = 'some string')
{
    var_dump($param);
}


function testFnc6(?string $param = null)
{
    var_dump($param);
}

Now we test the functions with different values.

fnc no argument null '' 'other string'
1 FATAL ERROR Uncaught ArgumentCountError FATAL ERROR Uncaught TypeError: Argument 1 passed to testFnc1() must be of the type string, null given string(0) "" string(12) "other string"
2 string(11) "some string" FATAL ERROR Uncaught TypeError: Argument 1 passed to testFnc2() must be of the type string, null given string(0) "" string(12) "other string"
3 NULL NULL string(0) "" string(12) "other string"
4 FATAL ERROR Uncaught ArgumentCountError NULL string(0) "" string(12) "other string"
5 string(11) "some string" NULL string(0) "" string(12) "other string"
6 NULL NULL string(0) "" string(12) "other string"

Notice the difference between testFnc3(string $param = null) and testFnc4(?string $param) when:

  1. no argument is passed
  2. the argument is null

You can call testFnc3() but not testFnc4() as it does not declare a default value.

You must call testFnc4(null).

So testFnc4(?string $param) allows $param to be null, but such parameter MUST be provided.