I would like or I will prefer indicate the real type of a parameter in a function with Php, it's possible ?
Example :
<?php
function test($param)
{
echo $param;
}
$str = "hiiiii everyone";
test($str);
?>
Instead of put just $param in the function test; I would like put something like that
function test(string $param) // string is the type of the param, that can be int, long ect or an object which I had created.
It's possible to do that with the last version of PHP ?
What you are looking for is Type Hinting. However, as stated in the linked manual page:
Type hints can not be used with scalar types such as int or string.
This means that no, you cannot force the argument for a function to be string. You can force it to be an instance of a specific class, something which is callable, or an array.
If you want to force an argument to be a string, do something like this:
function my_func ($mustBeAString) {
if (!is_string($mustBeAString)) return;
// Do stuff here
}
No. PHP is a dynamically typed language; variables (and as such, parameters) don't have set types. You could try and enforce your own thing using gettype, ie:
function test($param) {
if(gettype($param) != "string")
throw new TypeException //or something
}
But it's a bad idea. Don't try and implement features from other languages in a language you're new to. Just try and embrace the proper way and see how it goes from there.
Type Hinting was introduced in PHP5. You can now force parameters to be of a certain type by providing that type in the parameter list itself, as your example demonstrated.
Unfortunately, scalar objects (like int, and string) are not permitted.
You can do your own checking internally to determine whether the passed object is of the proper type using methods like gettype(), is_string() (handle other types as well), or even the type operator instanceof.
I would like to bring this to the table:
var_dump($str);
Related
I have been reading the "Visibility" section of the PHP manual, and in the first comment, someone mentions:
OUTSIDE CODE can cast Item properties to any other PHP types (booleans, integers, floats, strings, arrays, and objects etc.) -- another huge mistake.
Consider this example:
class base {
public $foo = 1;
}
$first = new base();
(string)$first->foo; //I thought just this expression would typecast
var_dump($first->foo); //but I found it still is int
$first->foo = (string)$first->foo;
var_dump($first->foo); //ok so public props can be typecasted
Is it just with the protected and private properties that we cannot change their type from outside? Or does that apply to public properties, too?
What you are doing is overwriting the property with a new value, which happens to be a different type.
Type casting does not affect the original variable or value. It creates a new value of the typecasted type that you need to assign if you want to preserve.
What you are asking has nothing to do with object properties visibility, but with understanding that typecasting is an operation that does not affect its operand.
This does absolutely nothing to $string:
$string = "123";
(int)$string;
... and the type casted value is lost since we are not assigning the result of the operation
With the following we can overwrite the value of $class::$someInteger, if a couple of conditions are met:
$class->someInteger = (string) 123;
That the property is public. (You obviously can't access directly private or protected properties from outside the class. You can cheat around this by using reflection or weird stuff like having a getter that returns a reference to the property, but both are very bad ideas for production code).
You are not using PHP 7.4 typed properties, and have declared a type for it.
The "permanently" part of the question is particularly misguided, since in PHP generally variables do not have types.
You can assign values of any type to any variable. And when they do have types (PHP 7.4 typed properties) there is no practical way of changing the defined type (again, there might be a way using reflection... but I'm not going there).
Your question is based upon the misunderstanding of the meaning of the term typecasting. The PHP Manual's page on type casting and the whole manual in general, is inadequate and is not a self-contained canonical reference for learning the php language. Plus, it assumes you to have knowledge of other programming languages such as C.
Typecasting is not defined as the data-type conversion of a variable; it is the data-type conversion of an expression -- In general, that is in most programming languages. Wikipedea defines it as following:
In computer science, type conversion, type casting, type coercion, and type juggling are different ways of changing an expression from one data type to another.
The official manual uses three terms namely, type juggling, type conversion and type casting. It can be guessed from the first paragraph that type juggling and type conversion are one and the same things. In the first paragraph they say:
Note that this does not change the types of the operands themselves; the only change is in how the operands are evaluated...
It should be clear that type juggling definitely doesn't change the type of the variable. From the php manual it appears as type juggling and type casting are two different concepts. The question is, since The PHP manual never defines these terms, how can we make sure if those two terms are same and what they actually mean. In the Type Casting article the manual says:
Type casting in PHP works much as it does in C:...
So, the answer is, we can safely assume that the definition of type casting from the C language applies to the PHP language. In C language type casting is defined same as the Wikipedia definition, that is only the expression's data type is converted. The following excerpts are taken from the book The C Programming Language by K&R, 2nd edition, section 2.7, page 45:
In the construction (type-name) expression, the expression is converted to the named type... ...The precise meaning of cast is as if the expression were assigned to a variable of the specific type... ...we can use sqrt((double) n)... ...Note that cast produces the value of n in the proper type, n itself is not altered.
This concludes the fact that type casting in php works the same way as type juggling in that the data type of variables(operands) being acted upon is not changed. You can rather use the function settype() to convert the data type of a variable.
As pointed out in the first paragraph, php manual's page on types gives the following technically wrong comment in their last paragraph:
To forcibly convert a variable to a certain type, either cast the variable or use the settype() function on it.
Now, you know what type casting in php actually means and why you had that misconception, it would be better to rephrase your question as following:
Rephrased question: How to permanently convert the data type of class properties in PHP.
It should be obvious that public properties will be converted to different type easily by settype($myObj->myPubProp, required-type). The interesting thing is, contrary to the suggestion made in user yivi's original answer, privated and protected properties can be assessed and can have their type converted from outside the class[1][2].
Method 1: Using references:
class myClass {
private $prop = 786; //Could be protected too.
public function &assess_priv(){
return $this->prop;
}
public function display_prop() {
echo var_dump($this->prop);
}
}
$obj = new myClass;
$newObjProp = &$obj->assess_priv();
settype($newObjProp, "string");
$obj->display_prop(); //converted the data type of private property of a class
Method 2: Using PHP property overloading
error_reporting(E_ALL);
class myClass {
private $prop = 786; //Could be protected too.
public function __set($name, $value)
{
$this->$name = $value;
}
public function __get($name)
{
return $this->$name;
}
}
$obj = new myClass;
var_dump($obj->prop);
$obj->prop = (string)$obj->prop; //Interestingly, settype($obj->prop, "string"); can't be used
echo "</br>";
var_dump($obj->prop); //converted the data type of private property of a class
Type casting class properties is now available in php7.4.
<?php
class User {
public int $id;
public string $name;
}
$user = new User;
$user->id = 123; // this will work
$user->id = "hello world"; // throws fatal error
Fatal error: Uncaught TypeError: Typed property
User::$id must be int, string used in [...][...]:7 Stack trace:
#0 {main} thrown in [...][...] on line 7
You need to switch to php7.4. This feature is now available in 7.4 link to their official docs
This is the sandbox link to try online.
Is this the accepted way to enforce a string constructor parameter in php:
public function __construct($myParameter)
{
if (! is_string($myParameter)) {
throw new InvalidArgumentException('My parameter must be a string');
}
$this->myParameter = $myParameter;
}
As PHP (prior to version 7) does not allow to typehint any simple types (int, string, boolean, float), but only arrays, classes and interfaces, such typecheck needs to be done manually. PHP provides a family of is_* functions that can help with checking the type of a variable: http://php.net/manual/en/ref.var.php
Answering your question, yes, what you provided is rather common way of enforcing type of function's arguments.
In some programming languages such as Java or C# it's allowed for programmer to set allowed input variable types. I use PHP and I want to do the same to avoid passing wrong data to my methods/functions.
My code:
public static function generateFiles(array $data, Custom_Pager $pager)
{...}
Why is that allowed and I cant write like that:
public static function generateFiles(array $data, Custom_Pager $pager, int $limit, string $text)
{ ... }
Is any way to standardize first and second method declarations I presented above? If no, why?
Yes, you can force the parameters to be of a certain type using type hinting, but it apparently does not work with primitive types.
You can, however, throw an exception in the method if the parameter values does not meet your expectations.
if (!is_int($param))
throw new Exception('param must be int.');
PHP is a weak-typed language, so that isn't possible.
PHP5.1 introduced Type Hinting, though it has it's limitations:
Type hints can not be used with scalar types such as int or string.
Traits are not allowed either.
I made a function to force type hinting. It works something like that:
function getVar($var,$type) {
switch($type) {
case "int":
return (int)$var;
case "string":
return (string)$var;
}
}
You can continue with all other types. Also you can make the same method to check variables for is_int, is_string, is_bool etc...
As an Emacs user, the only thing that I envy about "modern" editors like PDT is that PDT understands types, and even PHPDoc "type hints", e.g.
/**
* #param DateTime $date
* #param string $name
* #return DOMDocument
*/
Currently I use type hints wherever I can to make the PHP interpreter alert me if I get the parameter type wrong, but that only works if the parameter is an object. More importantly, there's no way to ensure that a function's return value is of a specific type.
This might be a long shot, but is there any plugin or other way of making the PHP interpreter aware of PHPDoc comments in the same way that PDT is? Ideally, I would like to get fatal errors if I return a value of the wrong type, or if I pass a string where I have declared the parameter as an int, for example.
You should look into the SplTypes extension (caution: it is experimental). That allows type hinting of "primitives" (last I heard they are better than primitives in every way imaginable).
You can't make the interpreter force primitives in any other way, though there are unimaginably annoying workaround which I will leave as an exercise for the reader.
No. PHP does not support explicit type declaration or type hinting, use of type juggling is explicitly part of the PHP interpreter. Per the documents on type hinting, only object and array type hints are supported.
That said, if you have a function with tight type requirements, it becomes essential to validate those arguments at the start of a function. If you are very attached to the idea of types in PHP, you can either a) switch to a typed language (heh), or b) use an autoboxing/object-wrapper pattern. There is a significant performance penalty to this, but instead of using primitive checks for type (ie is_string), you can create the wrapper class and use type hinting:
class StringWrapper {
public $value = null;
function __construct($val) {
$this->value = $val;
}
}
function requires_a_string(StringWrapper $string_value) {
echo $string_value->value;
}
$string = new StringWrapper('Hello world!');
As you can see, that's a pretty big hill to climb (with creating a wrapper for each type) just to avoid:
function requires_a_string($string_value='') {
if (!is_string($string_value))
return false;
echo $string_value;
}
My verdict is: not worth it.
You can read some more on autoboxing here: http://php.webtutor.pl/en/2011/04/13/strong-data-typing-in-php-part-ii-autoboxing-and-indestructable-objects-english-version/
Also, note this RFC for autoboxing: https://wiki.php.net/rfc/autoboxing It has been around for a while, though, so I wouldn't hold out for it.
It was big discussion how to make type hinting for scalar types:
Strongly check type
Try to juggle it always
Try to juggle it if obivios i.e '123' to int(123) but not '123aaa' to int(123)
But As far as I know now developers solution to not use scalar type hinting at all
PHP manual says:
Type Hints can only be of the object and array (since PHP 5.1) type. Traditional type hinting with int and string isn't supported.
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?
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
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).
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.
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.
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?
Because people are sick of using the is_* functions to validate parameters.
Reduction of redundant coding for defensive coders.
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..
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.
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;
}
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.