PHP type-hinting to primitive values?

PhpPrimitive TypesType Hinting

Php Problem Overview


I'd like to know whether one can type-hint a method to expect primitive types?

Something like this:

public function someMethod(string $str)
                         //^^^^^^

Or:

private function anotherMethod(int $num)
                             //^^^

the same way you would:

private function otherMethod(Person $rambo)
                           //^^^^^^

Is that possible in php?

Php Solutions


Solution 1 - Php

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

Solution 2 - Php

Nope. You can't type hint for primitives because PHP has automatic conversions for primitives. See http://bugs.php.net/bug.php?id=29508. This will never change, unless the PHP team has a sudden change of heart (which is doubtful, they're pretty stubborn).

Solution 3 - Php

Yes, Now its possible, After a long discussion, a proposal to implement type hinting for scalar function parameters and return values was just approved with the highest vote count so far, check for details :

Scalar type hinting consists of declaring the types of function parameters and return values that can be of the types int, float, string and bool.This allows the PHP runtime engine to check if the types of values passed to parameter functions and return values are of the expected types in order to detect eventual programming mistakes. Type hinting for objects, arrays and callables was already allowed in past PHP versions. The current implementation introduces five new reserved words: int, float, bool, string and numeric. These were not previously reserved, because casting is a special case in the lexer.

Example :
function test(float $a) {
    var_dump($a); 
}

test(1); // float(1)
test("1"); // float(1)
test(1.0); // float(1)
test("1a"); // E_RECOVERABLE_ERROR
test("a"); // E_RECOVERABLE_ERROR
test(""); // E_RECOVERABLE_ERROR
test(1.5); // float(1.5)
test(array()); // E_RECOVERABLE_ERROR
test(new StdClass); // E_RECOVERABLE_ERROR

You have also an option to declare into source file where you can allow Scaler type hinting.It must be 1st line of your config script and can’t be declared elsewhere in the same file.

Like : declare(strict_types=1);

At runtime, when the PHP engine tries to return a value, it will check if doesn’t match as declared it will throw a fatal error like, Fatal error: Argument 1 passed to increment() must be of the type integer, string given

With this new features of declaration, you can write more robust applications by detecting early programming mistakes caused by passing values of the wrong types to functions.

Automatic changes of types may also happen. For example, int types can be change into float type parameters automatically,

function test(float $x){
	var_dump($x);
}
test(10); // works fine

Declaring the Return Type

We can declare the return types adding a colon followed by the expected type between the last parenthesis and the first bracket in the function declaration.

For functions that do not return any value, nothing should be added in the return type declaration section.

function mustReturnInt(): int { ... }
function mustReturnString(): string { ... }
function mustReturnBool(): bool { ... }
function mustReturnFloat(): float { ... }
function doesNotReturnAnything() { ... }

A Little Bit more Complex Example

declare(strict_types=1);  
class StrictTypesTestingClass {  
public function returnSameInt(int $value): int {   return $value;  }   
public function returnSameFloat(float $value): float {   return $value;  }  
public function returnSameString(string $value): string {   return $value;  }   
public function returnSameBool(bool $value): bool {   return $value;  } }  
$check = new StrictTypesTestingClass();  // calls that work  print $check->returnSameInt(10); 
print $check->returnSameFloat(10.0); 
print $check->returnSameString("test"); 
print $check->returnSameBool(true) ? 'true' : 'false';  // calls that throw exceptions 
print $check->returnSameInt("10"); 
print $check->returnSameFloat("10.0"); 
print $check->returnSameString(10);
print $check->returnSameBool("true");

Behavior of Weak Type Checking and Type Conversion : The weak type checking mode can be used with the statement declare(strict_types=0); or the absence of the strict types declaration. There are a few of points to take into account: Weak type checked calls to an extension or built-in PHP function have the same behaviour as in previous PHP versions The weak type checking rules for new scalar type declarations are mostly the same as those of extension or built-in PHP functions. NULL is a special case in order to be consistent with the current type declarations for classes, callables and arrays. NULL is not accepted by default, unless it is a parameter and is explicitly given a default value of NULL, for instance: function sample(int $a = NULL);

There are a lots of advantages to this approach. You get type safety. Which means that you can finally statically analyze code! You can detect bugs where you accidentally take a string from one function and pass it as an integer to another.For me, a developer that uses PHP on a daily basis and sees Java as a reference for OOP languages, this is great progress for PHP.

Solution 4 - Php

Everyone already said it, you can't do type hint for primitives because PHP doest not support it. The reason behind this is not only related to automatic conversions but also to community reaction.

So far, I can remember that in May of 2010 support for scalar type hinting was added to the PHP trunk. But because of community response this feature didn't make it into the 5.4 release.

There was a bit of controversy about this. Those who opposed the change argued that this support would go against the fundamental designs of PHP. PHP is considered to be a weak typed language. In essence, this means that PHP does not require you to declare data types. Variables still have data types associated with them but you can do radical things like adding a string to an integer without resulting in an error.

IMHO: Scalar type hinting should be added into PHP ASAP, it's a feature we all need, I really respect that PHP is weak typed language, but for high end development and production, specially on OO contexts, scalar type hinting is a must have. We can have both alternatives in PHP, just like procedural and OO.

Solution 5 - Php

Yes, it is possible.

http://ru2.php.net/manual/ru/language.oop5.typehinting.php#83442

Warning: there is a typo in original manual: resrouce instead of resource

People often ask about scalar/basic typehints. Here is a drop in class that I use in my MVC framework that will enable typehints through the use of a custom error handler.

Note: You should include this code above all other code in your include headers and if you are the using set_error_handler() function you should be aware that this uses it as well. You may need to chain your set_error_handlers()

Why?

  1. Because people are sick of using the is_* functions to validate parameters.
  2. Reduction of redundant coding for defensive coders.
  3. Functions/Methods are self defining/documenting as to required input.

Also.. Follow the discussion for typehints in PHP 6.0 on the PHP Internals boards.

<?php

define('TYPEHINT_PCRE', '/^Argument (\d)+ passed to (?:(\w+)::)?(\w+)\(\) must be an instance of (\w+), (\w+) given/');

class Typehint
{

    private static $Typehints = array(
        'boolean'   => 'is_bool',
        'integer'   => 'is_int',
        'float'     => 'is_float',
        'string'    => 'is_string',
        'resource'  => 'is_resource'
    );

    private function __Constrct() {}

    public static function initializeHandler()
    {

        set_error_handler('Typehint::handleTypehint');

        return TRUE;
    }

    private static function getTypehintedArgument($ThBackTrace, $ThFunction, $ThArgIndex, &$ThArgValue)
    {

        foreach ($ThBackTrace as $ThTrace)
        {

            // Match the function; Note we could do more defensive error checking.
            if (isset($ThTrace['function']) && $ThTrace['function'] == $ThFunction)
            {

                $ThArgValue = $ThTrace['args'][$ThArgIndex - 1];

                return TRUE;
            }
        }

        return FALSE;
    }

    public static function handleTypehint($ErrLevel, $ErrMessage)
    {

        if ($ErrLevel == E_RECOVERABLE_ERROR)
        {

            if (preg_match(TYPEHINT_PCRE, $ErrMessage, $ErrMatches))
            {

                list($ErrMatch, $ThArgIndex, $ThClass, $ThFunction, $ThHint, $ThType) = $ErrMatches;

                if (isset(self::$Typehints[$ThHint]))
                {

                    $ThBacktrace = debug_backtrace();
                    $ThArgValue  = NULL;

                    if (self::getTypehintedArgument($ThBacktrace, $ThFunction, $ThArgIndex, $ThArgValue))
                    {

                        if (call_user_func(self::$Typehints[$ThHint], $ThArgValue))
                        {

                            return TRUE;
                        }
                    }
                }
            }
        }

        return FALSE;
    }
}

Typehint::initializeHandler();

?>

An are some examples of the class in use:

<?php

function teststring(string $string) { echo $string; }
function testinteger(integer $integer) { echo $integer; }
function testfloat(float $float) { echo $float; }

// This will work for class methods as well.

?>

You get the picture..

Solution 6 - Php

Accordind to PHP documentation type hinting is not supported for primitive types.

It's supported for classes and interfaces though.

Edit: I forgot to mention that's also supported for arrays.

Solution 7 - Php

Here is short syntax for forcing a boolean value out of a passed in parameter. If $state is true, then $this->is_active is set to true. For all other types of values it is set to false.

function set_active ( $state ) {
    $this->is_active = true === $state;
}

Solution 8 - Php

I guess you don't need type hinting for PHP because you're given type checking functions such as is_bool(), is_string() etc etc, so you could check whatever your trying to put into an argument against these functions before actually making it an argument, although the method they use to check array and object types would be much cleaner.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFelipeView Question on Stackoverflow
Solution 1 - PhpafuzzyllamaView Answer on Stackoverflow
Solution 2 - PhpRafe KettlerView Answer on Stackoverflow
Solution 3 - PhpPurushottamView Answer on Stackoverflow
Solution 4 - PhpTCB13View Answer on Stackoverflow
Solution 5 - PhpSerhii SmirnovView Answer on Stackoverflow
Solution 6 - PhpLuc MView Answer on Stackoverflow
Solution 7 - PhpLee BlueView Answer on Stackoverflow
Solution 8 - PhpCarwyn StephenView Answer on Stackoverflow