Skip to content

Scalar Type Hints #998

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c3c0f53
Scalar type hints with ZPP casting rules
hikari-no-yume Dec 13, 2014
75a225d
Do not make scalar type hints reserved words, merely reserve class name
hikari-no-yume Dec 27, 2014
d4dd2a9
Use new names of arg parsing functions
hikari-no-yume Dec 29, 2014
a13d134
Refactor scalar type hints implementation per Dmitry's patch
hikari-no-yume Dec 29, 2014
a03af7f
Fix class name prohibition to work for namespaced classes, too
hikari-no-yume Jan 4, 2015
1a28ad0
Forbid scalar type hint names for use, class_alias
hikari-no-yume Jan 6, 2015
5544e37
Inline
hikari-no-yume Jan 6, 2015
cc01e37
It Begins
hikari-no-yume Jan 10, 2015
02ec357
Per-file
hikari-no-yume Jan 12, 2015
fe663cc
Partial ZPP strictness implementation
hikari-no-yume Jan 13, 2015
ca49012
Add strict scalar types test
hikari-no-yume Jan 13, 2015
e1a2386
Shorten syntax to strict_types=1
hikari-no-yume Jan 25, 2015
b112c13
Test strict code calling weak code and vice-versa
hikari-no-yume Jan 25, 2015
2985944
Fix usage of zend_wrong_param_count in ext/mysqli
hikari-no-yume Jan 25, 2015
86b0685
Prefix zend_wrong_param_count with _ to discourage use
hikari-no-yume Jan 25, 2015
17b3707
Test strict code including weak code and vice-versa
hikari-no-yume Jan 25, 2015
c6e8048
Fix fix
hikari-no-yume Jan 25, 2015
187a95f
Test nested strict/weak function calls
hikari-no-yume Jan 25, 2015
0af3b7c
Test behaviour of weak type hints with references
hikari-no-yume Jan 25, 2015
cbbaea0
Fix merge error
hikari-no-yume Jan 29, 2015
c7719ab
Refactor typehint lookup
hikari-no-yume Feb 1, 2015
6b6b2b4
Implement scalar return types (strict only for now)
hikari-no-yume Feb 1, 2015
44ed070
Fix Gd usages of ZEND_WRONG_PARAM_COUNT, add usage note
hikari-no-yume Feb 1, 2015
5a7ac0f
Implement per-file strictness for scalar return types
hikari-no-yume Feb 1, 2015
0294485
Prevent "undefined variable opline" errors
hikari-no-yume Feb 2, 2015
b5513cd
Add scalar return types test
hikari-no-yume Feb 5, 2015
d6bea5b
Fixed use after free on the following code
dstogov Feb 10, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Zend/tests/is_a.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ function __autoload($name) {
class BASE {
}

interface INT {
interface I {
}

class A extends BASE implements INT {
class A extends BASE implements I {
}

$a = new A;
var_dump(is_a($a, "B1"));
var_dump(is_a($a, "A"));
var_dump(is_a($a, "BASE"));
var_dump(is_a($a, "INT"));
var_dump(is_a($a, "I"));
var_dump(is_subclass_of($a, "B2"));
var_dump(is_subclass_of($a, "A"));
var_dump(is_subclass_of($a, "BASE"));
var_dump(is_subclass_of($a, "INT"));
var_dump(is_subclass_of($a, "I"));

var_dump(is_subclass_of("X1", "X2"));
?>
Expand Down
14 changes: 14 additions & 0 deletions Zend/tests/typehints/explicit_weak_include_strict.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
explicitly strict_types=0 code including strict_types=1 code
--FILE--
<?php

declare(strict_types=0);

// file with strict_types=1
require 'weak_include_strict_2.inc';

// calls within that file should stay strict, despite being included by weak file
?>
--EXPECTF--
Catchable fatal error: Argument 1 passed to takes_int() must be of the type integer, float given, called in %sweak_include_strict_2.inc on line 9 and defined in %sweak_include_strict_2.inc on line 5
20 changes: 20 additions & 0 deletions Zend/tests/typehints/scalar_aliases.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
Scalar type hint aliases
--FILE--
<?php

function foo(integer $a, boolean $b) {
var_dump($a, $b);
}

function bar(int $a, bool $b) {
var_dump($a, $b);
}

foo(1, true);
bar(1, true);
--EXPECT--
int(1)
bool(true)
int(1)
bool(true)
241 changes: 241 additions & 0 deletions Zend/tests/typehints/scalar_basic.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
--TEST--
Scalar type hint basics
--FILE--
<?php

$errnames = [
E_NOTICE => 'E_NOTICE',
E_WARNING => 'E_WARNING',
E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR'
];
set_error_handler(function (int $errno, string $errmsg, string $file, int $line) use ($errnames) {
echo "$errnames[$errno]: $errmsg on line $line\n";
return true;
});

$functions = [
'int' => function (int $i) { return $i; },
'float' => function (float $f) { return $f; },
'string' => function (string $s) { return $s; },
'bool' => function (bool $b) { return $b; }
];

class Stringable {
public function __toString() {
return "foobar";
}
}

$values = [
1,
"1",
1.0,
1.5,
"1a",
"a",
"",
PHP_INT_MAX,
NAN,
TRUE,
FALSE,
NULL,
[],
new StdClass,
new Stringable,
fopen("data:text/plain,foobar", "r")
];

foreach ($functions as $type => $function) {
echo PHP_EOL, "Testing '$type' typehint:", PHP_EOL;
foreach ($values as $value) {
echo "*** Trying ";
var_dump($value);
var_dump($function($value));
}
}
--EXPECTF--

Testing 'int' typehint:
*** Trying int(1)
int(1)
*** Trying string(1) "1"
int(1)
*** Trying float(1)
int(1)
*** Trying float(1.5)
int(1)
*** Trying string(2) "1a"
E_NOTICE: A non well formed numeric value encountered on line %d
int(1)
*** Trying string(1) "a"
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, string given, called in %s on line %d and defined on line %d
string(1) "a"
*** Trying string(0) ""
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, string given, called in %s on line %d and defined on line %d
string(0) ""
*** Trying int(%d)
int(%d)
*** Trying float(NAN)
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, float given, called in %s on line %d and defined on line %d
float(NAN)
*** Trying bool(true)
int(1)
*** Trying bool(false)
int(0)
*** Trying NULL
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, null given, called in %s on line %d and defined on line %d
NULL
*** Trying array(0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, array given, called in %s on line %d and defined on line %d
array(0) {
}
*** Trying object(stdClass)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, object given, called in %s on line %d and defined on line %d
object(stdClass)#%s (0) {
}
*** Trying object(Stringable)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, object given, called in %s on line %d and defined on line %d
object(Stringable)#%s (0) {
}
*** Trying resource(%d) of type (stream)
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, resource given, called in %s on line %d and defined on line %d
resource(%d) of type (stream)

Testing 'float' typehint:
*** Trying int(1)
float(1)
*** Trying string(1) "1"
float(1)
*** Trying float(1)
float(1)
*** Trying float(1.5)
float(1.5)
*** Trying string(2) "1a"
E_NOTICE: A non well formed numeric value encountered on line %d
float(1)
*** Trying string(1) "a"
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, string given, called in %s on line %d and defined on line %d
string(1) "a"
*** Trying string(0) ""
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, string given, called in %s on line %d and defined on line %d
string(0) ""
*** Trying int(%d)
float(%s)
*** Trying float(NAN)
float(NAN)
*** Trying bool(true)
float(1)
*** Trying bool(false)
float(0)
*** Trying NULL
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, null given, called in %s on line %d and defined on line %d
NULL
*** Trying array(0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, array given, called in %s on line %d and defined on line %d
array(0) {
}
*** Trying object(stdClass)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, object given, called in %s on line %d and defined on line %d
object(stdClass)#%s (0) {
}
*** Trying object(Stringable)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, object given, called in %s on line %d and defined on line %d
object(Stringable)#%s (0) {
}
*** Trying resource(%d) of type (stream)
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, resource given, called in %s on line %d and defined on line %d
resource(%d) of type (stream)

Testing 'string' typehint:
*** Trying int(1)
string(1) "1"
*** Trying string(1) "1"
string(1) "1"
*** Trying float(1)
string(1) "1"
*** Trying float(1.5)
string(3) "1.5"
*** Trying string(2) "1a"
string(2) "1a"
*** Trying string(1) "a"
string(1) "a"
*** Trying string(0) ""
string(0) ""
*** Trying int(%d)
string(%d) "%d"
*** Trying float(NAN)
string(3) "NAN"
*** Trying bool(true)
string(1) "1"
*** Trying bool(false)
string(0) ""
*** Trying NULL
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type string, null given, called in %s on line %d and defined on line %d
NULL
*** Trying array(0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type string, array given, called in %s on line %d and defined on line %d
array(0) {
}
*** Trying object(stdClass)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type string, object given, called in %s on line %d and defined on line %d
object(stdClass)#%s (0) {
}
*** Trying object(Stringable)#%s (0) {
}
string(6) "foobar"
*** Trying resource(%d) of type (stream)
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type string, resource given, called in %s on line %d and defined on line %d
resource(%d) of type (stream)

Testing 'bool' typehint:
*** Trying int(1)
bool(true)
*** Trying string(1) "1"
bool(true)
*** Trying float(1)
bool(true)
*** Trying float(1.5)
bool(true)
*** Trying string(2) "1a"
bool(true)
*** Trying string(1) "a"
bool(true)
*** Trying string(0) ""
bool(false)
*** Trying int(%d)
bool(true)
*** Trying float(NAN)
bool(true)
*** Trying bool(true)
bool(true)
*** Trying bool(false)
bool(false)
*** Trying NULL
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type boolean, null given, called in %s on line %d and defined on line %d
NULL
*** Trying array(0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type boolean, array given, called in %s on line %d and defined on line %d
array(0) {
}
*** Trying object(stdClass)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type boolean, object given, called in %s on line %d and defined on line %d
object(stdClass)#%s (0) {
}
*** Trying object(Stringable)#%s (0) {
}
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type boolean, object given, called in %s on line %d and defined on line %d
object(Stringable)#%s (0) {
}
*** Trying resource(%d) of type (stream)
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type boolean, resource given, called in %s on line %d and defined on line %d
resource(%d) of type (stream)
55 changes: 55 additions & 0 deletions Zend/tests/typehints/scalar_none.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
--TEST--
Scalar type hint missing parameters
--FILE--
<?php

$errnames = [
E_NOTICE => 'E_NOTICE',
E_WARNING => 'E_WARNING',
E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR'
];
set_error_handler(function (int $errno, string $errmsg, string $file, int $line) use ($errnames) {
echo "$errnames[$errno]: $errmsg on line $line\n";
return true;
});

$functions = [
'int' => function (int $i) { return $i; },
'float' => function (float $f) { return $f; },
'string' => function (string $s) { return $s; },
'bool' => function (bool $b) { return $b; },
'int nullable' => function (int $i = NULL) { return $i; },
'float nullable' => function (float $f = NULL) { return $f; },
'string nullable' => function (string $s = NULL) { return $s; },
'bool nullable' => function (bool $b = NULL) { return $b; }
];

foreach ($functions as $type => $function) {
echo "Testing $type:", PHP_EOL;
var_dump($function());
}
--EXPECTF--
Testing int:
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type integer, none given, called in %s on line %d and defined on line %d
E_NOTICE: Undefined variable: i on line %d
NULL
Testing float:
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type float, none given, called in %s on line %d and defined on line %d
E_NOTICE: Undefined variable: f on line %d
NULL
Testing string:
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type string, none given, called in %s on line %d and defined on line %d
E_NOTICE: Undefined variable: s on line %d
NULL
Testing bool:
E_RECOVERABLE_ERROR: Argument 1 passed to {closure}() must be of the type boolean, none given, called in %s on line %d and defined on line %d
E_NOTICE: Undefined variable: b on line %d
NULL
Testing int nullable:
NULL
Testing float nullable:
NULL
Testing string nullable:
NULL
Testing bool nullable:
NULL
Loading