Skip to content

Commit 936d0ef

Browse files
committed
Implementation of function autoloading
1 parent 67b8e5c commit 936d0ef

35 files changed

+1236
-82
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Basic autoload_call_function() function
3+
--FILE--
4+
<?php
5+
function customAutoloader($class) {
6+
function test() {}
7+
}
8+
autoload_register_function('customAutoloader');
9+
10+
autoload_call_function('test');
11+
var_dump(function_exists('test', false));
12+
?>
13+
--EXPECT--
14+
bool(true)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
Test autoload_call_function() with invalid symbol name
3+
--FILE--
4+
<?php
5+
function customAutoloader($name) {
6+
var_dump($name);
7+
}
8+
autoload_register_function('customAutoloader');
9+
10+
try {
11+
autoload_call_function('12ayhs');
12+
} catch (\Throwable $e) {
13+
echo $e::class, ': ', $e->getMessage();
14+
}
15+
try {
16+
autoload_call_function('"');
17+
} catch (\Throwable $e) {
18+
echo $e::class, ': ', $e->getMessage();
19+
}
20+
try {
21+
autoload_call_function('');
22+
} catch (\Throwable $e) {
23+
echo $e::class, ': ', $e->getMessage();
24+
}
25+
try {
26+
autoload_call_function("al\no");
27+
} catch (\Throwable $e) {
28+
echo $e::class, ': ', $e->getMessage();
29+
}
30+
?>
31+
--EXPECT--
32+
string(6) "12ayhs"
33+
string(1) """
34+
string(0) ""
35+
string(4) "al
36+
o"
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Autoloader should not do anything magic with called scope
3+
--FILE--
4+
<?php
5+
6+
class Test {
7+
public static function register() {
8+
autoload_register_function([Test::class, 'autoload']);
9+
}
10+
11+
public static function autoload($class) {
12+
echo "self=" . self::class, ", static=", static::class, "\n";
13+
}
14+
}
15+
16+
class Test2 extends Test {
17+
public static function register() {
18+
autoload_register_function([Test2::class, 'autoload']);
19+
}
20+
21+
public static function runTest() {
22+
function_exists('FooBar');
23+
}
24+
}
25+
26+
Test::register();
27+
Test2::register();
28+
Test2::runTest();
29+
30+
?>
31+
--EXPECT--
32+
self=Test, static=Test
33+
self=Test, static=Test2
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
Dynamic autoload with invalid symbol name in variable
3+
--FILE--
4+
<?php
5+
function customAutoloader($name) {
6+
var_dump($name);
7+
}
8+
autoload_register_function('customAutoloader');
9+
$name = '12ayhs';
10+
11+
try {
12+
$name();
13+
} catch (\Throwable $e) {
14+
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
15+
}
16+
$name = '"';
17+
try {
18+
$name();
19+
} catch (\Throwable $e) {
20+
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
21+
}
22+
$name = '';
23+
try {
24+
$name();
25+
} catch (\Throwable $e) {
26+
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
27+
}
28+
$name = "al\no";
29+
try {
30+
$name();
31+
} catch (\Throwable $e) {
32+
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
33+
}
34+
?>
35+
--EXPECT--
36+
string(6) "12ayhs"
37+
Error: Call to undefined function 12ayhs()
38+
Error: Call to undefined function "()
39+
Error: Call to undefined function ()
40+
Error: Call to undefined function al
41+
o()
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
--TEST--
2+
Autoloading with closures and invocables
3+
--FILE--
4+
<?php
5+
$closure = function ($name) {
6+
echo 'autoload(' . $name . ")\n";
7+
};
8+
9+
class Autoloader {
10+
public function __construct(private string $dir) {}
11+
public function __invoke($func) {
12+
echo ("Autoloader('{$this->dir}') called with $func\n");
13+
}
14+
}
15+
16+
class WorkingAutoloader {
17+
public function __invoke($func) {
18+
echo ("WorkingAutoloader() called with $func\n");
19+
eval("function $func() { }");
20+
}
21+
}
22+
23+
$al1 = new Autoloader('d1');
24+
$al2 = new WorkingAutoloader('d2');
25+
26+
autoload_register_function($closure);
27+
autoload_register_function($al1);
28+
autoload_register_function($al2);
29+
30+
var_dump(autoload_list_function());
31+
32+
$foo = foo();
33+
34+
autoload_unregister_function($closure);
35+
autoload_unregister_function($al1);
36+
37+
$bar = bar();
38+
39+
?>
40+
--EXPECT--
41+
array(3) {
42+
[0]=>
43+
object(Closure)#1 (1) {
44+
["parameter"]=>
45+
array(1) {
46+
["$name"]=>
47+
string(10) "<required>"
48+
}
49+
}
50+
[1]=>
51+
object(Autoloader)#2 (1) {
52+
["dir":"Autoloader":private]=>
53+
string(2) "d1"
54+
}
55+
[2]=>
56+
object(WorkingAutoloader)#3 (0) {
57+
}
58+
}
59+
autoload(foo)
60+
Autoloader('d1') called with foo
61+
WorkingAutoloader() called with foo
62+
WorkingAutoloader() called with bar
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
Destructor call of autoloader when object freed
3+
--FILE--
4+
<?php
5+
class A {
6+
public $var = 1;
7+
public function autoload() {
8+
echo "var:".$this->var."\n";
9+
}
10+
public function __destruct() {
11+
echo "__destruct__\n";
12+
}
13+
}
14+
15+
$a = new A;
16+
$a->var = 2;
17+
18+
autoload_register_function(array($a, 'autoload'));
19+
unset($a);
20+
21+
var_dump(function_exists("C", true));
22+
?>
23+
===DONE===
24+
--EXPECT--
25+
var:2
26+
bool(false)
27+
===DONE===
28+
__destruct__
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Parse errors should be thrown if occuring from an autoloader
3+
--FILE--
4+
<?php
5+
6+
autoload_register_function(function($class) {
7+
eval("ha ha ha");
8+
});
9+
autoload_register_function(function($class) {
10+
echo "Don't call me.\n";
11+
});
12+
13+
foo();
14+
15+
?>
16+
--EXPECTF--
17+
Parse error: syntax error, unexpected identifier "ha" in %s on line %d
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Exception thrown from within autoloading function
3+
--FILE--
4+
<?php
5+
6+
function TestFunc1($classname) {
7+
echo __METHOD__ . "($classname)\n";
8+
}
9+
10+
function TestFunc2($classname) {
11+
echo __METHOD__ . "($classname)\n";
12+
throw new Exception("Function $classname missing");
13+
}
14+
15+
function TestFunc3($classname) {
16+
echo __METHOD__ . "($classname)\n";
17+
}
18+
19+
autoload_register_function("TestFunc1");
20+
autoload_register_function("TestFunc2");
21+
autoload_register_function("TestFunc3");
22+
23+
try {
24+
var_dump(function_exists("foo", true));
25+
} catch(Exception $e) {
26+
echo 'Exception: ' . $e->getMessage() . "\n";
27+
}
28+
29+
?>
30+
--EXPECT--
31+
TestFunc1(foo)
32+
TestFunc2(foo)
33+
Exception: Function foo missing
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
--TEST--
2+
Exceptions during autoloading
3+
--FILE--
4+
<?php
5+
6+
function MyAutoLoad($name)
7+
{
8+
echo __METHOD__ . "($name)\n";
9+
throw new Exception('Bla');
10+
}
11+
12+
class MyAutoLoader
13+
{
14+
static function autoLoad($name)
15+
{
16+
echo __METHOD__ . "($name)\n";
17+
throw new Exception('Bla');
18+
}
19+
20+
function dynaLoad($name)
21+
{
22+
echo __METHOD__ . "($name)\n";
23+
throw new Exception('Bla');
24+
}
25+
}
26+
27+
$obj = new MyAutoLoader;
28+
29+
$funcs = array(
30+
'MyAutoLoad',
31+
'MyAutoLoader::autoLoad',
32+
'MyAutoLoader::dynaLoad',
33+
array('MyAutoLoader', 'autoLoad'),
34+
array('MyAutoLoader', 'dynaLoad'),
35+
array($obj, 'autoLoad'),
36+
array($obj, 'dynaLoad'),
37+
);
38+
39+
foreach($funcs as $idx => $func)
40+
{
41+
echo "====$idx====\n";
42+
43+
var_dump($func);
44+
try {
45+
autoload_register_function($func);
46+
} catch (TypeError $e) {
47+
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
48+
var_dump(count(autoload_list_function()));
49+
continue;
50+
}
51+
52+
if (count(autoload_list_function())) {
53+
echo "registered\n";
54+
55+
try {
56+
var_dump(function_exists("foo", true));
57+
} catch (Exception $e) {
58+
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
59+
}
60+
}
61+
62+
autoload_unregister_function($func);
63+
var_dump(count(autoload_list_function()));
64+
}
65+
66+
?>
67+
--EXPECTF--
68+
====0====
69+
string(10) "MyAutoLoad"
70+
registered
71+
MyAutoLoad(foo)
72+
Exception: Bla
73+
int(0)
74+
====1====
75+
string(22) "MyAutoLoader::autoLoad"
76+
registered
77+
MyAutoLoader::autoLoad(foo)
78+
Exception: Bla
79+
int(0)
80+
====2====
81+
string(22) "MyAutoLoader::dynaLoad"
82+
TypeError: autoload_register_function(): Argument #1 ($callback) must be a valid callback, non-static method MyAutoLoader::dynaLoad() cannot be called statically
83+
int(0)
84+
====3====
85+
array(2) {
86+
[0]=>
87+
string(12) "MyAutoLoader"
88+
[1]=>
89+
string(8) "autoLoad"
90+
}
91+
registered
92+
MyAutoLoader::autoLoad(foo)
93+
Exception: Bla
94+
int(0)
95+
====4====
96+
array(2) {
97+
[0]=>
98+
string(12) "MyAutoLoader"
99+
[1]=>
100+
string(8) "dynaLoad"
101+
}
102+
TypeError: autoload_register_function(): Argument #1 ($callback) must be a valid callback, non-static method MyAutoLoader::dynaLoad() cannot be called statically
103+
int(0)
104+
====5====
105+
array(2) {
106+
[0]=>
107+
object(MyAutoLoader)#%d (0) {
108+
}
109+
[1]=>
110+
string(8) "autoLoad"
111+
}
112+
registered
113+
MyAutoLoader::autoLoad(foo)
114+
Exception: Bla
115+
int(0)
116+
====6====
117+
array(2) {
118+
[0]=>
119+
object(MyAutoLoader)#%d (0) {
120+
}
121+
[1]=>
122+
string(8) "dynaLoad"
123+
}
124+
registered
125+
MyAutoLoader::dynaLoad(foo)
126+
Exception: Bla
127+
int(0)

0 commit comments

Comments
 (0)