1--TEST--
2Return scalar type basics
3--SKIPIF--
4<?php if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only"); ?>
5--FILE--
6<?php
7
8$errnames = [
9    E_NOTICE => 'E_NOTICE',
10    E_WARNING => 'E_WARNING',
11    E_DEPRECATED => 'E_DEPRECATED',
12];
13set_error_handler(function (int $errno, string $errmsg, string $file, int $line) use ($errnames) {
14    echo "$errnames[$errno]: $errmsg on line $line\n";
15    return true;
16});
17
18$functions = [
19    'int' => function ($i): int { return $i; },
20    'float' => function ($f): float { return $f; },
21    'string' => function ($s): string { return $s; },
22    'bool' => function ($b): bool { return $b; }
23];
24
25class StringCapable {
26    public function __toString() {
27        return "foobar";
28    }
29}
30
31$values = [
32    1,
33    "1",
34    1.0,
35    1.5,
36    "1a",
37    "a",
38    "",
39    PHP_INT_MAX,
40    NAN,
41    TRUE,
42    FALSE,
43    NULL,
44    [],
45    new StdClass,
46    new StringCapable,
47    fopen("data:text/plain,foobar", "r")
48];
49
50foreach ($functions as $type => $function) {
51    echo PHP_EOL, "Testing '$type' type:", PHP_EOL;
52    foreach ($values as $value) {
53        echo "*** Trying ";
54        var_dump($value);
55        try {
56            var_dump($function($value));
57        } catch (TypeError $e) {
58            echo "*** Caught ", $e->getMessage(), " in ", $e->getFile(), " on line ", $e->getLine(), PHP_EOL;
59        }
60    }
61}
62
63echo PHP_EOL . "Done";
64?>
65--EXPECTF--
66Testing 'int' type:
67*** Trying int(1)
68int(1)
69*** Trying string(1) "1"
70int(1)
71*** Trying float(1)
72int(1)
73*** Trying float(1.5)
74E_DEPRECATED: Implicit conversion from float 1.5 to int loses precision on line %d
75int(1)
76*** Trying string(2) "1a"
77*** Caught {closure:%s:%d}(): Return value must be of type int, string returned in %s on line %d
78*** Trying string(1) "a"
79*** Caught {closure:%s:%d}(): Return value must be of type int, string returned in %s on line %d
80*** Trying string(0) ""
81*** Caught {closure:%s:%d}(): Return value must be of type int, string returned in %s on line %d
82*** Trying int(9223372036854775807)
83int(9223372036854775807)
84*** Trying float(NAN)
85*** Caught {closure:%s:%d}(): Return value must be of type int, float returned in %s on line %d
86*** Trying bool(true)
87int(1)
88*** Trying bool(false)
89int(0)
90*** Trying NULL
91*** Caught {closure:%s:%d}(): Return value must be of type int, null returned in %s on line %d
92*** Trying array(0) {
93}
94*** Caught {closure:%s:%d}(): Return value must be of type int, array returned in %s on line %d
95*** Trying object(stdClass)#6 (0) {
96}
97*** Caught {closure:%s:%d}(): Return value must be of type int, stdClass returned in %s on line %d
98*** Trying object(StringCapable)#7 (0) {
99}
100*** Caught {closure:%s:%d}(): Return value must be of type int, StringCapable returned in %s on line %d
101*** Trying resource(5) of type (stream)
102*** Caught {closure:%s:%d}(): Return value must be of type int, resource returned in %s on line %d
103
104Testing 'float' type:
105*** Trying int(1)
106float(1)
107*** Trying string(1) "1"
108float(1)
109*** Trying float(1)
110float(1)
111*** Trying float(1.5)
112float(1.5)
113*** Trying string(2) "1a"
114*** Caught {closure:%s:%d}(): Return value must be of type float, string returned in %s on line %d
115*** Trying string(1) "a"
116*** Caught {closure:%s:%d}(): Return value must be of type float, string returned in %s on line %d
117*** Trying string(0) ""
118*** Caught {closure:%s:%d}(): Return value must be of type float, string returned in %s on line %d
119*** Trying int(9223372036854775807)
120float(9.223372036854776E+18)
121*** Trying float(NAN)
122float(NAN)
123*** Trying bool(true)
124float(1)
125*** Trying bool(false)
126float(0)
127*** Trying NULL
128*** Caught {closure:%s:%d}(): Return value must be of type float, null returned in %s on line %d
129*** Trying array(0) {
130}
131*** Caught {closure:%s:%d}(): Return value must be of type float, array returned in %s on line %d
132*** Trying object(stdClass)#6 (0) {
133}
134*** Caught {closure:%s:%d}(): Return value must be of type float, stdClass returned in %s on line %d
135*** Trying object(StringCapable)#7 (0) {
136}
137*** Caught {closure:%s:%d}(): Return value must be of type float, StringCapable returned in %s on line %d
138*** Trying resource(5) of type (stream)
139*** Caught {closure:%s:%d}(): Return value must be of type float, resource returned in %s on line %d
140
141Testing 'string' type:
142*** Trying int(1)
143string(1) "1"
144*** Trying string(1) "1"
145string(1) "1"
146*** Trying float(1)
147string(1) "1"
148*** Trying float(1.5)
149string(3) "1.5"
150*** Trying string(2) "1a"
151string(2) "1a"
152*** Trying string(1) "a"
153string(1) "a"
154*** Trying string(0) ""
155string(0) ""
156*** Trying int(9223372036854775807)
157string(19) "9223372036854775807"
158*** Trying float(NAN)
159string(3) "NAN"
160*** Trying bool(true)
161string(1) "1"
162*** Trying bool(false)
163string(0) ""
164*** Trying NULL
165*** Caught {closure:%s:%d}(): Return value must be of type string, null returned in %s on line %d
166*** Trying array(0) {
167}
168*** Caught {closure:%s:%d}(): Return value must be of type string, array returned in %s on line %d
169*** Trying object(stdClass)#6 (0) {
170}
171*** Caught {closure:%s:%d}(): Return value must be of type string, stdClass returned in %s on line %d
172*** Trying object(StringCapable)#7 (0) {
173}
174string(6) "foobar"
175*** Trying resource(5) of type (stream)
176*** Caught {closure:%s:%d}(): Return value must be of type string, resource returned in %s on line %d
177
178Testing 'bool' type:
179*** Trying int(1)
180bool(true)
181*** Trying string(1) "1"
182bool(true)
183*** Trying float(1)
184bool(true)
185*** Trying float(1.5)
186bool(true)
187*** Trying string(2) "1a"
188bool(true)
189*** Trying string(1) "a"
190bool(true)
191*** Trying string(0) ""
192bool(false)
193*** Trying int(9223372036854775807)
194bool(true)
195*** Trying float(NAN)
196bool(true)
197*** Trying bool(true)
198bool(true)
199*** Trying bool(false)
200bool(false)
201*** Trying NULL
202*** Caught {closure:%s:%d}(): Return value must be of type bool, null returned in %s on line %d
203*** Trying array(0) {
204}
205*** Caught {closure:%s:%d}(): Return value must be of type bool, array returned in %s on line %d
206*** Trying object(stdClass)#6 (0) {
207}
208*** Caught {closure:%s:%d}(): Return value must be of type bool, stdClass returned in %s on line %d
209*** Trying object(StringCapable)#7 (0) {
210}
211*** Caught {closure:%s:%d}(): Return value must be of type bool, StringCapable returned in %s on line %d
212*** Trying resource(5) of type (stream)
213*** Caught {closure:%s:%d}(): Return value must be of type bool, resource returned in %s on line %d
214
215Done
216