Skip to content

Commit 15a7ebd

Browse files
authored
Add param defaults to reflection (of php-ast's functions) in php 8 (nikic#152)
Add param defaults to reflection in php 8 Support generated arginfo macros in older php versions Throw in `new ast\Node` for invalid parameter types in php 7. (already the default for php 8)
1 parent f958360 commit 15a7ebd

File tree

6 files changed

+160
-41
lines changed

6 files changed

+160
-41
lines changed

ast.c

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,29 @@
1414
#include "zend_exceptions.h"
1515
#include "zend_smart_str.h"
1616

17+
#ifndef ZEND_ARG_INFO_WITH_DEFAULT_VALUE
18+
#define ZEND_ARG_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, default_value) \
19+
ZEND_ARG_INFO(pass_by_ref, name)
20+
#endif
21+
#if PHP_VERSION_ID < 70200
22+
#undef ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX
23+
#define ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \
24+
static const zend_internal_arg_info name[] = { \
25+
{ (const char*)(zend_uintptr_t)(required_num_args), ( #class_name ), 0, return_reference, allow_null, 0 },
26+
#endif
27+
28+
#ifndef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX
29+
#define ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(name, return_reference, required_num_args, class_name, allow_null) \
30+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, class_name, allow_null)
31+
#endif
32+
33+
#ifndef ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE
34+
#define ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, type_hint, allow_null, default_value) \
35+
ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null)
36+
#endif
37+
38+
#include "ast_arginfo.h"
39+
1740
#define ast_throw_exception(exception_ce, ...) \
1841
zend_throw_exception_ex(exception_ce, 0, __VA_ARGS__)
1942

@@ -1242,7 +1265,7 @@ PHP_METHOD(ast_Node, __construct) {
12421265
zend_long lineno;
12431266
zend_bool kindNull, flagsNull, linenoNull;
12441267

1245-
ZEND_PARSE_PARAMETERS_START(0, 4)
1268+
ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_THROW, 0, 4)
12461269
Z_PARAM_OPTIONAL
12471270
Z_PARAM_LONG_EX(kind, kindNull, 1, 0)
12481271
Z_PARAM_LONG_EX(flags, flagsNull, 1, 0)
@@ -1278,39 +1301,6 @@ PHP_METHOD(ast_Node, __construct) {
12781301
}
12791302
}
12801303

1281-
ZEND_BEGIN_ARG_INFO_EX(arginfo_parse_file, 0, 0, 2)
1282-
ZEND_ARG_INFO(0, filename)
1283-
ZEND_ARG_INFO(0, version)
1284-
ZEND_END_ARG_INFO()
1285-
1286-
ZEND_BEGIN_ARG_INFO_EX(arginfo_parse_code, 0, 0, 2)
1287-
ZEND_ARG_INFO(0, code)
1288-
ZEND_ARG_INFO(0, version)
1289-
ZEND_ARG_INFO(0, filename)
1290-
ZEND_END_ARG_INFO()
1291-
1292-
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_kind_name, 0, 0, 1)
1293-
ZEND_ARG_INFO(0, kind)
1294-
ZEND_END_ARG_INFO()
1295-
1296-
ZEND_BEGIN_ARG_INFO_EX(arginfo_kind_uses_flags, 0, 0, 1)
1297-
ZEND_ARG_INFO(0, kind)
1298-
ZEND_END_ARG_INFO()
1299-
1300-
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_metadata, 0, 0, 0)
1301-
ZEND_END_ARG_INFO()
1302-
1303-
ZEND_BEGIN_ARG_INFO_EX(arginfo_get_supported_versions, 0, 0, 0)
1304-
ZEND_ARG_INFO(0, exclude_deprecated)
1305-
ZEND_END_ARG_INFO()
1306-
1307-
ZEND_BEGIN_ARG_INFO_EX(arginfo_node_construct, 0, 0, 0)
1308-
ZEND_ARG_INFO(0, kind)
1309-
ZEND_ARG_INFO(0, flags)
1310-
ZEND_ARG_ARRAY_INFO(0, children, 1)
1311-
ZEND_ARG_INFO(0, lineno)
1312-
ZEND_END_ARG_INFO()
1313-
13141304
const zend_function_entry ast_functions[] = {
13151305
ZEND_NS_FE("ast", parse_file, arginfo_parse_file)
13161306
ZEND_NS_FE("ast", parse_code, arginfo_parse_code)
@@ -1322,7 +1312,7 @@ const zend_function_entry ast_functions[] = {
13221312
};
13231313

13241314
const zend_function_entry ast_node_functions[] = {
1325-
PHP_ME(ast_Node, __construct, arginfo_node_construct, ZEND_ACC_PUBLIC)
1315+
PHP_ME(ast_Node, __construct, arginfo_class_Node___construct, ZEND_ACC_PUBLIC)
13261316
PHP_FE_END
13271317
};
13281318

ast.stub.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
/**
4+
* USE ast_stub.php INSTEAD IF YOU ARE LOOKING FOR DOCUMENTATION OR STUBS FOR YOUR IDE.
5+
*
6+
* This is a stub file meant only for use with https://github.com/php/php-src/blob/master/build/gen_stub.php
7+
* to generate Reflection information (ReflectionParameter, ReflectionFunction, ReflectionMethod, etc.)
8+
*/
9+
10+
// XXX: build/gen_stub.php does not support namespace nodes at the time of writing.
11+
// The namespace is thus deliberately omitted so that ast_arginfo.h can be successfully built.
12+
// namespace ast;
13+
14+
15+
/**
16+
* Parses code file and returns AST root node.
17+
*
18+
* @param string $filename Code file to parse
19+
* @param int $version AST version
20+
* @return Node Root node of AST
21+
*
22+
* @see https://github.com/nikic/php-ast for version information
23+
*/
24+
function parse_code(string $code, int $version, string $filename = 'string code'): \ast\Node {}
25+
26+
function parse_file(string $filename, int $version): \ast\Node {}
27+
28+
/**
29+
* @param int $kind AST_* constant value defining the kind of an AST node
30+
* @return string String representation of AST kind value
31+
*/
32+
function get_kind_name(int $kind): string {}
33+
34+
/**
35+
* @param int $kind AST_* constant value defining the kind of an AST node
36+
* @return bool Returns true if AST kind uses flags
37+
*/
38+
function kind_uses_flags(int $kind): bool {}
39+
40+
/**
41+
* Provides metadata for the AST kinds.
42+
*
43+
* The returned array is a map from AST kind to a Metadata object.
44+
*
45+
* @return Metadata[] Metadata about AST kinds
46+
*/
47+
function get_metadata(): array {}
48+
49+
/**
50+
* Returns currently supported AST versions.
51+
*
52+
* @param bool $exclude_deprecated Whether to exclude deprecated versions
53+
* @return int[] Array of supported AST versions
54+
*/
55+
function get_supported_versions(bool $exclude_deprecated = false): array {}
56+
57+
/**
58+
* This class describes a single node in a PHP AST.
59+
*/
60+
class Node
61+
{
62+
/**
63+
* A constructor which accepts any types for the properties.
64+
* For backwards compatibility reasons, all values are optional and can be any type, and properties default to null
65+
*
66+
* @param int|null $kind
67+
* @param int|null $flags
68+
* @param array|null $children
69+
* @param int|null $lineno
70+
*/
71+
public function __construct(?int $kind = null, ?int $flags = null, ?array $children = null, ?int $lineno = null) {
72+
}
73+
}
74+

ast_arginfo.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* This is a generated file, edit the .stub.php file instead.
2+
* Stub hash: 6c168364b94be45e237e47fd5709046457c6cb6b */
3+
4+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_parse_code, 0, 2, ast\\Node, 0)
5+
ZEND_ARG_TYPE_INFO(0, code, IS_STRING, 0)
6+
ZEND_ARG_TYPE_INFO(0, version, IS_LONG, 0)
7+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, filename, IS_STRING, 0, "\'string code\'")
8+
ZEND_END_ARG_INFO()
9+
10+
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_parse_file, 0, 2, ast\\Node, 0)
11+
ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0)
12+
ZEND_ARG_TYPE_INFO(0, version, IS_LONG, 0)
13+
ZEND_END_ARG_INFO()
14+
15+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_get_kind_name, 0, 1, IS_STRING, 0)
16+
ZEND_ARG_TYPE_INFO(0, kind, IS_LONG, 0)
17+
ZEND_END_ARG_INFO()
18+
19+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_kind_uses_flags, 0, 1, _IS_BOOL, 0)
20+
ZEND_ARG_TYPE_INFO(0, kind, IS_LONG, 0)
21+
ZEND_END_ARG_INFO()
22+
23+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_get_metadata, 0, 0, IS_ARRAY, 0)
24+
ZEND_END_ARG_INFO()
25+
26+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_get_supported_versions, 0, 0, IS_ARRAY, 0)
27+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, exclude_deprecated, _IS_BOOL, 0, "false")
28+
ZEND_END_ARG_INFO()
29+
30+
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Node___construct, 0, 0, 0)
31+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, kind, IS_LONG, 1, "null")
32+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 1, "null")
33+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, children, IS_ARRAY, 1, "null")
34+
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, lineno, IS_LONG, 1, "null")
35+
ZEND_END_ARG_INFO()

ast_stub.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@
217217
*
218218
* @see https://github.com/nikic/php-ast for version information
219219
*/
220-
function parse_file($filename, $version)
220+
function parse_file(string $filename, int $version)
221221
{
222222
}
223223

@@ -231,23 +231,23 @@ function parse_file($filename, $version)
231231
*
232232
* @see https://github.com/nikic/php-ast for version information
233233
*/
234-
function parse_code($code, $version, $filename = "string code")
234+
function parse_code(string $code, int $version, string $filename = "string code")
235235
{
236236
}
237237

238238
/**
239239
* @param int $kind AST_* constant value defining the kind of an AST node
240240
* @return string String representation of AST kind value
241241
*/
242-
function get_kind_name($kind)
242+
function get_kind_name(int $kind): string
243243
{
244244
}
245245

246246
/**
247247
* @param int $kind AST_* constant value defining the kind of an AST node
248248
* @return bool Returns true if AST kind uses flags
249249
*/
250-
function kind_uses_flags($kind)
250+
function kind_uses_flags(int $kind): bool
251251
{
252252
}
253253

@@ -258,7 +258,7 @@ function kind_uses_flags($kind)
258258
*
259259
* @return Metadata[] Metadata about AST kinds
260260
*/
261-
function get_metadata()
261+
function get_metadata(): array
262262
{
263263
}
264264

@@ -268,7 +268,7 @@ function get_metadata()
268268
* @param bool $exclude_deprecated Whether to exclude deprecated versions
269269
* @return int[] Array of supported AST versions
270270
*/
271-
function get_supported_versions($exclude_deprecated = false)
271+
function get_supported_versions($exclude_deprecated = false): array
272272
{
273273
}
274274

package.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
<notes>
3232
- Support attributes syntax change (`#[...]`) in php 8.0.0RC1.
3333
- Change the current AST version from 70 to 80. AST version 80 is no longer experimental.
34+
- Add `ReflectionParameter` defaults for `ast\parse_code` and `ast\get_supported_versions` in php 8.
35+
- Add parameter types and return types to reflection for various global functions.
36+
php-ast was already throwing a `TypeError` when invalid parameter types were received.
37+
- Always throw instead of warning when invalid parameters are passed to the ast\Node constructor.
3438
</notes>
3539
<contents>
3640
<dir name="/">
@@ -39,6 +43,7 @@
3943
<file name="util.php" role="doc" />
4044
<file name="ast.c" role="src" />
4145
<file name="ast_data.c" role="src" />
46+
<file name="ast_arginfo.h" role="src" />
4247
<file name="ast_str_defs.h" role="src" />
4348
<file name="ast_stub.php" role="doc" />
4449
<file name="LICENSE" role="doc" />
@@ -85,6 +90,7 @@
8590
<file name="named_children.phpt" role="test" />
8691
<file name="name_node.phpt" role="test" />
8792
<file name="nested_stmt_lists.phpt" role="test" />
93+
<file name="node_constructor_throw.phpt" role="test" />
8894
<file name="nop_statements.phpt" role="test" />
8995
<file name="nullable_types.phpt" role="test" />
9096
<file name="object_type.phpt" role="test" />

tests/node_constructor_throw.phpt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
new ast\Node() throwing
3+
--SKIPIF--
4+
<?php if (!extension_loaded("ast")) print "skip"; ?>
5+
--FILE--
6+
<?php
7+
8+
try {
9+
new ast\Node('invalid');
10+
} catch (TypeError $e) {
11+
echo "Caught {$e->getMessage()}\n";
12+
}
13+
--EXPECTF--
14+
Caught %s, string given

0 commit comments

Comments
 (0)