suppress new PHP-7.4 notice about failed stream_write
[m6w6/ext-http] / scripts / gen_stubs.php
1 #!/usr/bin/env php
2 <?php
3
4 function m($m, $c = null) {
5 $n = "";
6 if ($c && $c->isInterface()) {
7 $m ^= ReflectionMethod::IS_ABSTRACT;
8 }
9 foreach (Reflection::getModifierNames($m) as $mn) {
10 $n .= $mn . " ";
11 }
12 return $n;
13 }
14 function t(ReflectionParameter $p) {
15 if ($c = $p->getClass()) return ($p->allowsNull()?"?":"") . "\\" . $c->getName() . " ";
16 if ($p->isArray()) return ($p->allowsNull() ? "?":"") . "array ";
17 if ($p->hasType()) {
18 return ($p->allowsNull() ? "?" : "") . ($p->getType()->isBuiltin() ? "" : "\\") . $p->getType()->getName() . " ";
19 }
20 }
21 function c($n, $c) {
22 $_=$c;
23 while ($c = $c->getParentClass()) {
24 if (array_key_exists($n, $c->getConstants())) {
25 return false;
26 }
27 }
28 $c=$_;
29 foreach ((array) $c->getInterfaces() as $i) {
30 if (array_key_exists($n, $i->getConstants()) || !c($n, $i)) {
31 return false;
32 }
33 }
34 return true;
35 }
36
37 ob_start(function($s) {
38 // redirect any output to stderr
39 fwrite(STDERR, $s);
40 return true;
41 });
42
43 $out = STDOUT;
44 switch ($argc) {
45 default:
46 case 3:
47 $out = fopen($argv[2], "w") or die;
48 case 2:
49 $ext = $argv[1];
50 break;
51
52 case 1:
53 die(sprintf($out, "Usage: %s <ext>\n", $argv[0]));
54 }
55
56 fprintf($out, "<?php\n\n");
57
58 $ext = new ReflectionExtension($ext);
59
60 $constants = array();
61 $functions = array();
62 $structures = array();
63
64 // split up by namespace first
65 foreach ($ext->getConstants() as $constant => $value) {
66 $ns = ($nsend = strrpos($constant, "\\")) ? substr($constant, 0, $nsend++) : "";
67 $cn = substr($constant, $nsend);
68 $constants[$ns][$cn] = $value;
69 }
70 foreach ($ext->getFunctions() as $f) {
71 /* @var $f ReflectionFunction */
72 $ns = $f->inNamespace() ? $f->getNamespaceName() : "";
73 $functions[$ns][$f->getShortName()] = $f;
74 }
75 foreach ($ext->getClasses() as $c) {
76 /* @var $c ReflectionClass */
77 $ns = $c->inNamespace() ? $c->getNamespaceName() : "";
78 $structures[$ns][$c->getShortName()] = $c;
79 }
80
81 $namespaces = array_unique(array_merge(
82 array_keys($constants),
83 array_keys($functions),
84 array_keys($structures)
85 ));
86
87 // simple sort
88 natsort($namespaces);
89
90 foreach ($namespaces as $ns) {
91 fprintf($out, "namespace %s%s\n{\n", $ns, strlen($ns) ? " " : "");
92 //
93 if (isset($constants[$ns])) {
94 ksort($constants[$ns], SORT_NATURAL);
95 foreach ($constants[$ns] as $cn => $value) {
96 fprintf($out, "\tconst %s = %s;\n", $cn, var_export($value, true));
97 }
98 }
99 //
100 if (isset($functions[$ns])) {
101 ksort($functions[$ns], SORT_NATURAL);
102 foreach ($functions[$ns] as $fn => $f) {
103 /* @var $f ReflectionFunction */
104 fprintf($out, "\n\tfunction %s(", $fn);
105 $ps = array();
106 foreach ($f->getParameters() as $p) {
107 $p1 = sprintf("%s%s\$%s", t($p),
108 $p->isPassedByReference()?"&":"", trim($p->getName(), "\""));
109 if ($p->isOptional()) {
110 if ($p->isDefaultValueAvailable()) {
111 $p1 .= sprintf(" = %s",
112 var_export($p->getDefaultValue(), true));
113 } elseif (!($p->isArray() || $p->getClass()) || $p->allowsNull()) {
114 $p1 .= " = NULL";
115 } elseif ($p->isArray()) {
116 $p1 .= " = array()";
117 }
118 }
119 $ps[] = $p1;
120 }
121 fprintf($out, "%s)", implode(", ", $ps));
122 if ($f->hasReturnType()) {
123 fprintf($out, " : %s%s", $f->getReturnType()->allowsNull() ? "?":"", $f->getReturnType()->getName());
124 }
125 fprintf($out, " {\n\t}\n");
126 }
127 }
128 //
129 if (isset($structures[$ns])) {
130 uasort($structures[$ns], function ($a, $b) {
131 /* @var $a ReflectionClass */
132 /* @var $b ReflectionClass */
133 $score = array_sum([
134 -!$a->isInterface()+
135 -!$a->isAbstract()+
136 -!$a->isTrait()+
137 -!substr_compare($a->getShortName(), "Exception", -strlen("Exception")),
138 +!$b->isInterface()+
139 +!$b->isAbstract()+
140 +!$b->isTrait()+
141 -!substr_compare($b->getShortName(), "Exception", -strlen("Exception")),
142 ]);
143
144 if ($score) {
145 return -$score;
146 }
147 return strnatcmp($a->getShortName(), $b->getShortName());
148 });
149 foreach ($structures[$ns] as $cn => $c) {
150 fprintf($out, "\n\t%s%s %s ", m($c->getModifiers()),
151 $c->isInterface() ? "interface":"class", $c->getShortName());
152 if ($p = $c->getParentClass()) {
153 fprintf($out, "extends \\%s ", $p->getName());
154 }
155 if ($i = $c->getInterfaceNames()) {
156 fprintf($out, "%s \\%s ",
157 $c->isInterface() ? "extends" : "implements",
158 implode(", \\", array_filter($i, function($v) use($c, $i) {
159 foreach ($i as $ii) {
160 if ($v != $ii && (new ReflectionClass($ii))->implementsInterface("\\".$v)) {
161 return false;
162 }
163 }
164 return $v != "Traversable";
165
166 }))
167 );
168 }
169 fprintf($out, "\n\t{\n");
170
171 $_=0;
172 foreach ($c->getConstants() as $n => $v) {
173 c($n, $c) and $_+=fprintf($out, "\t\tconst %s = %s;\n", $n,
174 var_export($v, true));
175 }
176 $_ and fprintf($out, "\n");
177 $_=0;
178 foreach ($c->getProperties() as $p) {
179 if ($p->getDeclaringClass()->getName() == $c->getName()) {
180 $_+=fprintf($out, "\t\t%s\$%s;\n", m($p->getModifiers()),
181 $p->getName());
182 }
183 }
184 $_ and fprintf($out, "\n");
185
186 foreach ($c->getMethods() as $m) {
187 if ($m->getDeclaringClass()->getName() == $c->getName()) {
188 fprintf($out, "\t\t%sfunction %s(", m($m->getModifiers(), $c),
189 $m->getName());
190 $ps = array();
191 foreach ($m->getParameters() as $p) {
192 $p1 = sprintf("%s%s\$%s", t($p),
193 $p->isPassedByReference()?"&":"", $p->getName());
194 if ($p->isOptional()) {
195 if ($p->isDefaultValueAvailable()) {
196 $p1 .= sprintf(" = %s",
197 var_export($p->getDefaultValue(), true));
198 } elseif (!($p->isArray() || $p->getClass()) || $p->allowsNull()) {
199 $p1 .= sprintf(" = NULL");
200 } elseif ($p->isArray()) {
201 $p1 .= " = array()";
202 }
203 }
204 $ps[] = $p1;
205 }
206 fprintf($out, "%s)", implode(", ", $ps));
207 if ($m->hasReturnType()) {
208 fprintf($out, " : %s%s%s", $m->getReturnType()->allowsNull() ? "?":"",
209 $m->getReturnType()->isBuiltin() ? "" : "\\", //0 === strpos($m->getReturnType()->getName(), $c->getNamespaceName()) ? "\\":"",
210 $m->getReturnType()->getName());
211 }
212 if ($m->isAbstract()) {
213 fprintf($out, ";\n\n");
214 } else {
215 fprintf($out, " {\n\t\t}\n\n");
216 }
217 }
218 }
219
220 fprintf($out, "\t}\n");
221
222 }
223 }
224 //
225 fprintf($out, "}\n\n");
226 }