1--TEST--
2Ensure type hints are enforced for functions invoked as callbacks.
3--FILE--
4<?php
5  set_error_handler('myErrorHandler', E_RECOVERABLE_ERROR);
6  function myErrorHandler($errno, $errstr, $errfile, $errline) {
7      echo "$errno: $errstr - $errfile($errline)\n";
8      return true;
9  }
10
11  echo "---> Type hints with callback function:\n";
12  class A  {  }
13  function f1(A $a)  {
14      echo "in f1;\n";
15  }
16  function f2(A $a = null)  {
17      echo "in f2;\n";
18  }
19  try {
20    call_user_func('f1', 1);
21  } catch (Error $ex) {
22    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
23  }
24  try {
25    call_user_func('f1', new A);
26  } catch (Error $ex) {
27    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
28  }
29  try {
30    call_user_func('f2', 1);
31  } catch (Error $ex) {
32    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
33  }
34  try {
35    call_user_func('f2');
36  } catch (Error $ex) {
37    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
38  }
39  try {
40    call_user_func('f2', new A);
41  } catch (Error $ex) {
42    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
43  }
44  try {
45    call_user_func('f2', null);
46  } catch (Error $ex) {
47    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
48  }
49
50  echo "\n\n---> Type hints with callback static method:\n";
51  class C {
52      static function f1(A $a) {
53          if (isset($this)) {
54              echo "in C::f1 (instance);\n";
55          } else {
56              echo "in C::f1 (static);\n";
57          }
58      }
59      static function f2(A $a = null) {
60          if (isset($this)) {
61              echo "in C::f2 (instance);\n";
62          } else {
63              echo "in C::f2 (static);\n";
64          }
65      }
66  }
67
68  try {
69    call_user_func(array('C', 'f1'), 1);
70  } catch (Error $ex) {
71    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
72  }
73  try {
74    call_user_func(array('C', 'f1'), new A);
75  } catch (Error $ex) {
76    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
77  }
78  try {
79    call_user_func(array('C', 'f2'), 1);
80  } catch (Error $ex) {
81    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
82  }
83  try {
84    call_user_func(array('C', 'f2'));
85  } catch (Error $ex) {
86    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
87  }
88  try {
89    call_user_func(array('C', 'f2'), new A);
90  } catch (Error $ex) {
91    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
92  }
93  try {
94    call_user_func(array('C', 'f2'), null);
95  } catch (Error $ex) {
96    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
97  }
98
99  echo "\n\n---> Type hints with callback instance method:\n";
100  class D {
101      function f1(A $a) {
102          if (isset($this)) {
103              echo "in C::f1 (instance);\n";
104          } else {
105              echo "in C::f1 (static);\n";
106          }
107      }
108      function f2(A $a = null) {
109          if (isset($this)) {
110              echo "in C::f2 (instance);\n";
111          } else {
112              echo "in C::f2 (static);\n";
113          }
114      }
115  }
116  $d = new D;
117
118  try {
119    call_user_func(array($d, 'f1'), 1);
120  } catch (Error $ex) {
121    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
122  }
123  try {
124    call_user_func(array($d, 'f1'), new A);
125  } catch (Error $ex) {
126    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
127  }
128  try {
129    call_user_func(array($d, 'f2'), 1);
130  } catch (Error $ex) {
131    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
132  }
133  try {
134    call_user_func(array($d, 'f2'));
135  } catch (Error $ex) {
136    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
137  }
138  try {
139    call_user_func(array($d, 'f2'), new A);
140  } catch (Error $ex) {
141    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
142  }
143  try {
144    call_user_func(array($d, 'f2'), null);
145  } catch (Error $ex) {
146    echo "{$ex->getCode()}: {$ex->getMessage()} - {$ex->getFile()}({$ex->getLine()})\n\n";
147  }
148
149?>
150--EXPECTF--
151---> Type hints with callback function:
1520: Argument 1 passed to f1() must be an instance of A, integer given%s(%d)
153
154in f1;
1550: Argument 1 passed to f2() must be an instance of A, integer given%s(%d)
156
157in f2;
158in f2;
159in f2;
160
161
162---> Type hints with callback static method:
1630: Argument 1 passed to C::f1() must be an instance of A, integer given%s(%d)
164
165in C::f1 (static);
1660: Argument 1 passed to C::f2() must be an instance of A, integer given%s(%d)
167
168in C::f2 (static);
169in C::f2 (static);
170in C::f2 (static);
171
172
173---> Type hints with callback instance method:
1740: Argument 1 passed to D::f1() must be an instance of A, integer given%s(%d)
175
176in C::f1 (instance);
1770: Argument 1 passed to D::f2() must be an instance of A, integer given%s(%d)
178
179in C::f2 (instance);
180in C::f2 (instance);
181in C::f2 (instance);
182