forked from mongodb/mongo-php-driver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerate-functionmap.php
138 lines (108 loc) · 4.35 KB
/
generate-functionmap.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<?php
if (PHP_VERSION_ID < 80000) {
echo 'This script requires PHP 8.0 or higher';
exit(1);
}
$filename = __DIR__ . '/functionmap.php';
(new FunctionMapGenerator)->createFunctionMap($filename);
printf("Created call map in %s\n", $filename);
class FunctionMapGenerator
{
public function createFunctionMap(string $filename): void
{
$this->writeFunctionMap($filename, $this->getFunctionMap());
}
private function getFunctionMap(): array
{
$classes = array_filter(get_declared_classes(), $this->filterItems(...));
$interfaces = array_filter(get_declared_interfaces(), $this->filterItems(...));
$functions = array_filter(get_defined_functions()['internal'], $this->filterItems(...));
$functionMap = [];
// Generate call map for functions
foreach ($functions as $functionName) {
$reflectionFunction = new ReflectionFunction($functionName);
$functionMap[$reflectionFunction->getName()] = $this->getFunctionMapEntry($reflectionFunction);
}
// Generate call map for classes and interfaces
$members = array_merge($classes, $interfaces);
sort($members);
$skippedMethods = ['__set_state', '__wakeup', '__serialize', '__unserialize'];
foreach ($members as $member) {
$reflectionClass = new ReflectionClass($member);
foreach ($reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
if ($method->getDeclaringClass() != $reflectionClass && $method->getName() != '__toString') {
continue;
}
if (in_array($method->getName(), $skippedMethods, true)) {
continue;
}
$methodKey = $reflectionClass->getName() . '::' . $method->getName();
$functionMap[$methodKey] = $this->getFunctionMapEntry($method);
}
}
return $functionMap;
}
private function writeFunctionMap(string $filename, array $functionMap): void
{
$lines = [];
foreach ($functionMap as $methodName => $typeInfo) {
$generatedTypeInfo = implode(
', ',
array_map(
function (string|int $key, string $value): string {
if (is_int($key)) {
return $this->removeDoubleBackslash(var_export($value, true));
}
return sprintf('%s => %s', var_export($key, true), $this->removeDoubleBackslash(var_export($value, true)));
},
array_keys($typeInfo),
array_values($typeInfo)
)
);
$lines[] = sprintf(
' %s => [%s],',
$this->removeDoubleBackslash(var_export($methodName, true)),
$generatedTypeInfo
);
}
$fileTemplate = <<<'PHP'
<?php
$mongoDBFunctionMap = [
%s
];
PHP;
file_put_contents($filename, sprintf($fileTemplate, implode("\n", $lines)));
}
private function filterItems(string $name): bool {
$namespaces = ['MongoDB\BSON\\', 'MongoDB\Driver\\'];
$name = strtolower($name);
foreach ($namespaces as $namespace) {
// Always compare lowercase names, as get_defined_functions lowercases function names by default
if (str_starts_with($name, strtolower($namespace))) {
return true;
}
}
return false;
}
private function getFunctionMapEntry(ReflectionFunctionAbstract $function): array
{
$returnType = match(true) {
$function->hasReturnType() => (string) $function->getReturnType(),
$function->hasTentativeReturnType() => (string) $function->getTentativeReturnType(),
default => 'void',
};
$functionMapEntry = [$returnType];
foreach ($function->getParameters() as $parameter) {
$parameterKey = $parameter->getName();
if ($parameter->isOptional()) {
$parameterKey .= '=';
}
$functionMapEntry[$parameterKey] = (string) $parameter->getType();
}
return $functionMapEntry;
}
private function removeDoubleBackslash(string $string): string
{
return str_replace('\\\\', '\\', $string);
}
}