Is it possible to specify multiple return types on PHP 7?
Solution 1:
As of PHP 8+, you may use union types:
function test(): FailObject|SuccessObject {}
Another way, available in all versions since PHP 4, is for the two objects to share an interface. Example:
interface ReturnInterface {}
class FailObject implements ReturnInterface {}
class SuccessObject implements ReturnInterface {}
function test(): ReturnInterface {}
In this example, ReturnInterface
is empty. Its mere presence supports the needed return type declaration.
You could also use a base, possibly abstract, class.
To me, for this use case, interfaces are more clear and more extensible than union types. For example, if I later want a WarnObject
I need only to define it as extending ReturnInterface
-- rather than going through all signatures and updating them to FailObject|SuccessObject|WarnObject
.
Solution 2:
As noted by bishop, there is an RFC for adding multiple return types. However, I thought I'd add that as of PHP7.1 you can now specify a nullable return type like this:
function exampleFunction(string $input) : ?int
{
// Do something
}
So this function would take in a string and by adding the question mark before int you are allowing it to return either null or an integer.
Here's a link to the documentation: http://php.net/manual/en/functions.returning-values.php
And here's a quote from that page explaining the usage: PHP 7.1 allows for void and null return types by preceding the type declaration with a ? — (e.g. function canReturnNullorString(): ?string)
Also, here's another thread that relates to this: Nullable return types in PHP7
Solution 3:
PHP from 7.2 onward supports the object return type
http://php.net/manual/en/migration72.new-features.php
function test(object $obj) : object
// return any type of object ...
Solution 4:
Since PHP 8.0 this is possible.
You can now use union types to specify this:
function test(): Success|Failure
{
if ($this->condition === false) {
return new Failure();
}
return new Success();
}
The fact that this is possible does not mean that it is always advisable. In many (probably most) situations, using an interface (e.g. Result
, which both Failure
and Failure
would implement) as advised in a different answer, is still much preferable.
But there are other instances where union types could make sense to an alternative to weak typing. E.g. a method that accepts both string
and int
, or to describe the return type of a function like stripos()
, which returns int|false
.