Viewed   110 times

PHP 7 introduces return type declarations. Which means I can now indicate the return value is a certain class, interface, array, callable or one of the newly hintable scalar types, as is possible for function parameters.

function returnHello(): string {
    return 'hello';
}

Often it happens that a value is not always present, and that you might return either something of some type, or null. While you can make parameters nullable by setting their default to null (DateTime $time = null), there does not appear to be a way to do this for return types. Is that indeed the case, or am I somehow not finding how to do it? These do not work:

function returnHello(): string? {
    return 'hello';
}

function returnHello(): string|null {
    return 'hello';
}

 Answers

5

PHP 7.1 Now supports nullable return types. The first RFC I linked to is the one they went for:

function nullOrString(int $foo) : ?string
{
    return $foo%2 ? "odd" : null;
}

old answer:

Since my comment was actually an answer to the question:

PHP 7 won't support nullable return-types just yet, but there's an RFC out to address just that, it aims to land in PHP 7.1. If it passes, the syntax would then affect all type-hints (both return types and type-hints):

public function returnStringOrNull(?array $optionalArray) : ?string
{
    if ($optionalArray) {
        return implode(', ', $optionalArray);//string returned here
    }
    return null;
}

There's also a competing RFC to add union types, which would be able to do the same thing, but would look different:

public function returnStringOrNull(array|null $optionalArray) : string|null
{
    if ($optionalArray) {
        return implode(', ', $optionalArray);//string returned here
    }
    return null;
}

For now, though, you'll have to write:

public function returnStringOrNull( array $optionalArray = null)
{
    if ($optionalArray) {
        return implode(', ', $optionalArray);
    }
}

Or just return an empty string to be consistent with the return type, and check falsy value:

public function returnStringOrNull( array $optionalArray = null) : string
{
    if ($optionalArray) {
        return implode(', ', $optionalArray);
    }
    return '';
}
//call
$string = $x->returnStringOrNull();
if (!$string) {
    $string = $x->returnStringOrNull(range(1, 10));
}
Monday, October 31, 2022
4

From the documentation

class typing.Union

Union type; Union[X, Y] means either X or Y.

Hence the proper way to represent more than one return data type is

from typing import Union


def foo(client_id: str) -> Union[list,bool]

But do note that typing is not enforced. Python continues to remain a dynamically-typed language. The annotation syntax has been developed to help during the development of the code prior to being released into production. As PEP 484 states, "no type checking happens at runtime."

>>> def foo(a:str) -> list:
...     return("Works")
... 
>>> foo(1)
'Works'

As you can see I am passing a int value and returning a str. However the __annotations__ will be set to the respective values.

>>> foo.__annotations__ 
{'return': <class 'list'>, 'a': <class 'str'>}

Please Go through PEP 483 for more about Type hints. Also see What are Type hints in Python 3.5?

Kindly note that this is available only for Python 3.5 and upwards. This is mentioned clearly in PEP 484.

Sunday, September 18, 2022
 
krezus
 
2

You're looking for Optional.

Since your return type can either be datetime (as returned from datetime.utcnow()) or None you should use Optional[datetime]:

from typing import Optional

def get_some_date(some_argument: int=None) -> Optional[datetime]:
    # as defined

From the documentation on typing, Optional is shorthand for:

Optional[X] is equivalent to Union[X, None].

where Union[X, Y] means a value of type X or Y.


If you want to be explicit due to concerns that others might stumble on Optional and not realize it's meaning, you could always use Union:

from typing import Union

def get_some_date(some_argument: int=None) -> Union[datetime, None]:

But I doubt this is a good idea, Optional is an indicative name and it does save a couple of keystrokes.

As pointed out in the comments by @Michael0x2a Union[T, None] is tranformed to Union[T, type(None)] so no need to use type here.

Visually these might differ but programatically, in both cases, the result is exactly the same; Union[datetime.datetime, NoneType] will be the type stored in get_some_date.__annotations__*:

>>> from typing import get_type_hints
>>> print(get_type_hints(get_some_date))
{'return': typing.Union[datetime.datetime, NoneType],
 'some_argument': typing.Union[int, NoneType]}

*Use typing.get_type_hints to grab the objects' __annotations__ attribute instead of accessing it directly.

Friday, December 16, 2022
 
firebug
 
4

You were very close. Just write your method like this:

[return: MaybeNull]
public T Get<T>(string key)
{
    var wrapper = cacheService.Get(key);
    return wrapper.HasValue ? Deserialize<T>(wrapper) : default!;
}

You have to use the default! to get rid of the warning. But you can tell the compiler with [return: MaybeNull] that it should check for null even if it's a non-nullable type.

In that case, the dev may get a warning (depends on flow analytics) if he uses your method and does not check for null.

For further info, see Microsoft documentation: Specify post-conditions: MaybeNull and NotNull

Thursday, October 27, 2022
1

This is strictly a style issue.

No matter where you write the annotation in the source code, the annotation is actually on the method. That's because of the @Target meta-annotation on the definition of javax.annotation.Nullable, which makes javax.annotation.Nullable a method annotation. You are allowed to write the annotation in either location, because the Java Language Specification grammar permits method annotations to be interspersed with method modifiers such as public.

I consider it clearer to place the annotation before the return type. After all, it's the return type that is non-null. It doesn't make sense to say that a method itself is non-null.

Placing the annotation before the return type has another important benefit: your code is compatible with versions of Nullable that are defined as type annotations. Type annotations were introduced in Java 8. They are more expressive than method annotations, and they enable more powerful checking. For example, the Nullable annotations supported by Eclipse and the Checker Framework are type annotations.

Tuesday, August 23, 2022
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :