- Bypassing a Slow Composer Repository
- Slow Composer Followup
- Getting Started with PHP Composer and Magento
- PHP: The Right Way; A Review
- PSR and Code Style Guidelines
- Sellvana: Developer’s Alpha Review
- PHP Primer: Type Hints
- PHP Primer: Namespaces
- PHP Primer: Interfaces
- Design Patterns, PHP, and Magento
- PHP-FPM and File Permissions
- Why did the Elephant join the Guild?
Today we’re going to give you a quick overview of PHP type hints. While the debate over how strongly PHP should be typed rages on, many PHP frameworks have started using type hints as metadata for implementing features like dependency injection. Whatever you think of strong typing or “magic” features like dependency injections, understanding type hints in the core PHP language is a de-facto responsibility for the modern PHP programmer.
The Problem
Let’s consider this simple PHP program.
<?php
#File: program.php
class Person
{
public function getHelloMessage()
{
return 'Hello world!';
}
}
function sayHello($object)
{
echo $object->getHelloMessage(),"\n";
}
$person = new Person;
sayHello($person);
Nothing too complicated here, we
- Define a class named
Person
- Define a function named
sayHello
-
Instantiate an object from the class
Person
-
Pass the person object to the
sayHello
function
If we take a closer look at the sayHello
function
function sayHello($object)
{
echo $object->getHelloMessage(),"\n";
}
We see it accepts a single parameter, and then echo
s the output of that parameter’s getHelloMessage
method. Run the program, and you’ll see the following output.
$ php program.php
Hello world!
While simple, this program is not without its problems. Let’s say we change the sayHello
function call
<?php
sayHello('Hola Mundo!');
If you run your program with the above function call, you’ll get the following error.
PHP Fatal error: Call to a member function getHelloMessage() on a non-object
That’s because we tried to pass this function a PHP string, when it expected an object. We’d have a similar problem if we passed the wrong sort of object to the function. The following call
sayHello((new stdClass));
Would spit out the following error message.
Fatal error: Call to undefined method stdClass::getHelloMessage()
If we know how to use our sayHello
function, this isn’t a problem. However, other programmers who might want to use the sayHello
function are left guessing as to what sort of variables its parameters accept. In our example this isn’t a real problem — the function is simple enough that a quick scan of its code tells us that $object
needs to have a getHelloMessage
method. However, for more complicated functions, not knowing what to pass in can be a real problem.
This is the problem type hints set out to solve.
The Solution
Type hints are pretty simple. Instead of writing a function like this
function sayHello($object)
{
echo $object->getHelloMessage(),"\n";
}
We change the function prototype to include a “type” for each method parameter.
function sayHello(Hello $object)
{
echo $object->getHelloMessage(),"\n";
}
In plain english, the above code says
The sayHello function accepts a single parameter named
$object
, and that object must be an object instantiated from theHello
class, or haveHello
in its ancestry chain.
With the above sayHello
function in place, if we tried running a program that passed in incorrect arguments
sayHello('Hola Mundo!');
sayHello((new stdClass));
We’d get different error messages
PHP Catchable fatal error: Argument 1 passed to sayHello() must be an instance of Person, instance of stdClass given
PHP Catchable fatal error: Argument 1 passed to sayHello() must be an instance of Person, string given
At first blush, this may make type hints seem useless — our program is still crashing with an error. If we look at bit deeper, there are a few benefits.
First, we get a better error message. PHP tells us which function argument is the problem
Argument 1 passed to sayHello
It also tells us what the problem was
must be an instance of Person, string given
In addition, passing an incorrect argument type is a different sort of PHP error, alluded to by the PHP error message.
PHP Catchable fatal error
Without the type hint, our program crashed with one of the following fatal errors
Call to a member function of a non-object
Call to undefined method
These are fatal, crashing, PHP errors that can’t be recovered from.
An argument not matching a type hint, however, raises a “less fatal” error. Specifically, a E_RECOVERABLE_ERROR
error. While serious, this error can be recovered from in a custom error handler (set with set_error_handler
).
Also, before we get on to the limitations of PHP’s type hinting system, we should point out that the word Catchable can throw some developers for a loop. Catchable here refers to the fact you can “catch” the error in a custom error handler, not that you can catch it in an actual try/catch
block. PHP error handling is confusing and awful.
Limitations
So that’s a very brief overview of PHP’s type hinting system. As per usual, if you’re interested in learning more [the PHP manual](Today we’re going to give you a quick overview of PHP type hints is a great place to start.
If you work with Java of C# developers, you may wonder why they occasionally sneer (or stare blankly) at PHP’s type hinting system. Java and C# are compiled languages. That means a programmer’s workflow is to
- Write the program
- Compile the program
- Run the program
These languages also require that every variable declaration include a type. Instead of saying
$foo = 27;
You need to say something like
Int $foo = 27;
These languages also require that you use types in your function parameters (i.e. PHP’s type hinting), and that each and every function have a return type set.
While this is a lot of extra work, and can turn off a lot of programmers just getting into the field, one benefit is the sort of errors we saw in our PHP program above can’t happen in these languages. The compiler refuses to compile a program with typing errors. This means those programs can never be run, and the programmer is forced the fix these errors before shipping.
Because PHP doesn’t have a compile step, and because the language will silently change a variable’s type for you behind the scenes, this sort of type safety is impossible in PHP, and for developers coming into PHP from these compiled languages, type hints can seem a little silly or weak.
Whether type hints are worth using is a question for each individual PHP team to decide on their own — but as we’ll see in my upcoming articles on Magento 2’s object system — many frameworks are using PHP type hints for things the core language never intended. You may not like PHP type hints, but they’re a part of the language and culture of PHP now, so make sure you know how they work.