(When) Should I Use Type Hinting 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.)

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.

Is it possible to type hint more than one type?

Academically, this is called a type union.

Union types in PHP

You can cheat by creating interfaces, parent types, etc, as mentioned in other answers, but what's the point, apart for adding complexity and LoCs to your project? Plus, that can't work for scalar types as you can't extend/implement a scalar type.

Instead of making the code more readable, you'll get the opposite. Except if those classes/interfaces already existed and they are here because of OOP, not to solve a type hinting problem.

Workarounds

The canonical answer in PHP is... well, just don't put a type hint. The language was not thought to have a complex and powerful type system, and trying to workaround the flaws of the language is not a good answer.

Instead, document your function properly:

/**
* Description of what the function does.
*
* @param User|File $multiTypeArgument Description of the argument.
*
* @return string[] Description of the function's return value.
*/
function myFunction($multiTypeArgument)
{

This will at least bring IDE support for autocompletion and static code analysis. Well enough when working on a private project, website, etc.

When designing a public API (a PHP library, etc), sometimes you may want to be more defensive about API consumers' inputs.

Then @tilz0R answer is the way to go:

function log($message) {
if (!is_string($message) && !$message instanceof Message) {
throw new \InvalidArgumentException('$message must be a string or a Message object.');
}

// code ...
}

The day PHP (almost) had union types

The 14th of February 2015, the Union Types PHP RFC was proposed for PHP 7.1. After discussion and vote, it's been rejected, 18 "no" against 11 "yes".

If the RFC had been accepted, PHP would have had union types exactly the way you've shown (User|File).

The RFC had some flaws, but the main reason for why it's been rejected is that the mainteners voters are quite resistive to change especially when it's about type strictness and other programming paradigms (ex. "why would we need type unions when the default takes all types of values" and "that's not good for performance").

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

Difference between Dependency Injection , Type Hinting and Composition in PHP OOP

Dependancy injection is providing your application what it needs to function, which is any data. Most application are modular, they behave like separte components or entities. But all need to take in something to function.

So, that thing they need is their dependancy.

This can be passed via a class contructor, which is ideal as when the an object is initialized the contructor is the first function that gets called, so anything your app needs to work can be passed via the constructor. But sometimes you can pass the data directly to the method as an argument to your function/method Ex:

# Generic Input validator
class InputValidator{
function isEmailValid($email){}
}

# Our main application
class UserRegistration(){
function Register($inputValidator){
$isEmailValid = $inputValidator->isEmailValid('foo@bar.com');
}
}

# Instanciating the class and providing the dependancy
(new UserRegistration)->Register(new InputValidator());

In the above example, the UserRegistration->Register() depends on the class InputValidator() to register a user, we could have provided the email validator directly in the UserRegistration class, but we choose to pass it as a dependancy instead make our application as a whole S.O.L.I.D compliant.

So, in short we are injecting the dependancy there. That is dependancy injection.

Type Hinting is, much simpler to understand.

Basically, if we extend our previous example and if you check Register(new InputValidator()); you can see that we passed it the
class it needs to function, but someone mistakenly could also pass another class or even a string such as: Register('something'); which would break the application, since
Method Register does not need a string. To prevent this, we can typehint it, in other words tell the Register function only to accept
certain type of data : array, object, int ... or we can even explicitly inform it to take a class name by providing it before as

$InputValidator = new InputValidator(); 
Register(InputValidator $InputValidator);

as for composition, this is a better read that I can provide What is composition as it relates to object oriented design?

php type hinting for object type

Type-hinting for a generic object doesn't yet exist in PHP, but should be available from version 7.2.0 onwards as a result of RFC Object typehint which passed by 32 votes to 3 on 31st May 2017.

Although normally (where possible) it is still better to type-hint to a specific class or interface.



Related Topics



Leave a reply



Submit