Why Is Type Hinting Necessary in PHP

Why is type hinting necessary in PHP?

Type hinting isn't required, but it can allow you to catch certain types of mistakes. For example, you might have a function or method which requires an integer. PHP will happily convert "number looking strings" into integers, and this can cause hard to debug behaviour. If you specify in your code that you specifically need an integer, this can prevent those kinds of bugs in the first place. Many programmers consider protecting their code in this way to be a best practice.

As a concrete example of this in action, let's look at an updated version of your index.php file:

index.php

<?php
include 'Song.php';
include 'Test.php';

$song_object = new Song;
$test_object = new Test;

$song_object->title = "Beat it!";
$song_object->lyrics = "It doesn't matter who's wrong or right... just beat it!";

$test_object->title = "Test it!";
$test_object->lyrics = "It doesn't matter who's wrong or right... just test it!";

function sing(Song $song)
{
echo "Singing the song called " . $song->title;
echo "<p>" . $song->lyrics . "</p>";
}

sing($song_object);
sing($test_object);

As well as the new Test.php file I added:

Test.php

<?php

class Test
{
public $title;
public $lyrics;
}

When I run index.php now, I get the following error:

Output:

Singing the song called Beat it!<p>It doesn't matter who's wrong or right...
just beat it!</p>PHP Catchable fatal error: Argument 1 passed to sing() must
be an instance of Song, instance of Test given, called in test/index.php on
line 22 and defined in test/index.php on line 15

Catchable fatal error: Argument 1 passed to sing() must be an instance of
Song, instance of Test given, called in test/index.php on line 22 and defined
in test/index.php on line 15

This is PHP letting me know that I tried to use the wrong type of class when I called the sing() function.

This is useful because, even though the above example worked, the Test class could be different than the Song class. This could lead to hard to debug errors later on. Using hinting in this way gives developers a way to prevent type errors before they cause issues. This is especially useful in a language like PHP which is often eager to auto-convert between types.

(When) should I use type hinting in PHP?

It's not about static vs dynamic typing, php is still dynamic. It's about contracts for interfaces. If you know a function requires an array as one of its parameters, force it right there in the function definition. I prefer to fail fast, rather than erroring later down in the function.

(Also note that you cant specify type hinting for bool, int, string, float, which makes sense in a dynamic context.)

Why is traditional type-hinting not allowed in PHP?

PHP's loosely typed, where your "primitive" types are automatically type-juggled based on the context in which they're used. Type-hinting wouldn't really change that, since a string could be used as an int, or vice versa. Type-hinting would only really be helpful for complex types like arrays and objects, which can't be cleanly juggled as ints, strings, or other primitives.

To put it another way, since PHP has no concept of specific types, you couldn't require an int somewhere because it doesn't know what an int really is. On the other hand, an object is of a certain type, since a MyClass is not interchangeable with a MyOtherClass.


Just for reference, here's what happens when you try to convert between such types (not an exhaustive list):

Converting to Object (ref)

"If an object is converted to an object, it is not modified. If a value of any other type is converted to an object, a new instance of the stdClass built-in class is created. If the value was NULL, the new instance will be empty. Arrays convert to an object with properties named by keys, and corresponding values. For any other value, a member variable named scalar will contain the value."

Object to int/float (ref)

undefined behavior

Object to boolean (ref)

in PHP5, always TRUE

Object to string (ref)

The object's __toString() magic method will be called, if applicable.

Object to array (ref)

"If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible; private variables have the class name prepended to the variable name; protected variables have a '*' prepended to the variable name. These prepended values have null bytes on either side. This can result in some unexpected behaviour."

Array to int/float (ref)

undefined behavior

Array to boolean (ref)

If the array is empty (i.e., no elements), it evaluates to FALSE -- otherwise, TRUE.

Array to string (ref)

the string "Array"; use print_r() or var_dump() to print the contents of an array

Array to object (ref)

"Arrays convert to an object with properties named by keys, and corresponding values."

Is type hinting helping the performance of PHP scripts?

PHP is a dynamic language.

Dynamic languages only support runtime checking.

Type hinting is runtime type checking.

Runtime type checking is bad for performance.

Therefore, type hinting is bad for performance.

Type Hinting: Default Parameters

You can't typehint strings, you can only typehint objects and arrays, so this is incorrect:

function setName ( string $name = "happ") {

(The reason you don't get a compile-time error here is because PHP is interpreting "string" as the name of a class.)

The wording in the docs means that if you do this:

function foo(Foo $arg) {

Then the argument passed to foo() must be an instance of object Foo. But if you do this:

function foo(Foo $arg = null) {

Then the argument passed to foo() can either be an instance of object Foo, or null. Note also that if you do this:

function foo(array $foo = array(1, 2, 3))

Then you can't call foo(null). If you want this functionality, you can do something like this:

function foo(array $foo = null) {
if ($foo === null) {
$foo = array(1, 2, 3);
}

[Edit 1] As of PHP 5.4, you can typehint callable:

function foo(callable $callback) {
call_user_func($callback);
}

[Edit 2] As of PHP 7.0, you can typehint bool, float, int, and string. This makes the code in the question valid syntax. As of PHP 7.1, you can typehint iterable.

Do I typehint everything in PHP?

Type hinting is the way to go. I would start with type hinting arguments (combined with interfaces), return values, and whenever you initialize a variable or property. Combined with doc blocks, and you have just documented your code in a way that allows others to pickup quickly.

function getValue(\Settings\Bar $foo) : string
{

$val = (string) $foo->value;
//..

return $val;
}
$myVal = (string) getValue($bar);

If anyone makes a mistake, the debugger will pinpoint you the exact location. Moreover use

declare(strict_types=1);

at the top of all your php pages to enforce type hinting and you are on your way to write enterprise level code using PHP.

When type hinting a class in PHP, do you need to include the class file?

This is not an authoritative response.

I can imagine that PHP objects internally have a field where the class name is stored. This could be used for the argument check.

In the case where the object is a valid instance of Foo (and you want to use it) you will already need the definition of Foo else you can't make an instance.

So it seems like the argument check doesn't need the definition of Foo.

PHP type-hinting to primitive values?

In PHP 7 they added the following:

Type declarations allow functions to require that parameters are of a certain type at call time. If the given value is of the incorrect type, then an error is generated: in PHP 5, this will be a recoverable fatal error, while PHP 7 will throw a TypeError exception.

Reference:
http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration


When this answer was asked, PHP 5 was the latest and said the following:

PHP 5 introduces type hinting. Functions are now able to force parameters to be objects (by specifying the name of the class in the function prototype), interfaces, arrays (since PHP 5.1) or callable (since PHP 5.4). However, if NULL is used as the default parameter value, it will be allowed as an argument for any later call.

If class or interface is specified as type hint then all its children or implementations are allowed too.

Type hints cannot be used with scalar types such as int or string. Resources and Traits are not allowed either.

Reference: http://php.net/manual/en/language.oop5.typehinting.php



Related Topics



Leave a reply



Submit