Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -3650,6 +3650,7 @@ static void zend_disable_function(const char *function_name, size_t function_nam
(function_name_length == strlen("exit") && !memcmp(function_name, "exit", strlen("exit")))
|| (function_name_length == strlen("die") && !memcmp(function_name, "die", strlen("die")))
|| (function_name_length == strlen("clone") && !memcmp(function_name, "clone", strlen("clone")))
|| (function_name_length == strlen("array") && !memcmp(function_name, "array", strlen("array")))
)) {
zend_error(E_WARNING, "Cannot disable function %s()", function_name);
return;
Expand Down
17 changes: 14 additions & 3 deletions Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -2173,9 +2173,20 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
zend_ast_export_list(str, zend_ast_get_list(ast), 1, 20, indent);
break;
case ZEND_AST_ARRAY:
smart_str_appendc(str, '[');
zend_ast_export_list(str, zend_ast_get_list(ast), 1, 20, indent);
smart_str_appendc(str, ']');
switch (ast->attr) {
case ZEND_ARRAY_SYNTAX_LONG:
case ZEND_ARRAY_SYNTAX_FUNCTION:
smart_str_appends(str, "array(");
zend_ast_export_list(str, zend_ast_get_list(ast), 1, 20, indent);
smart_str_appendc(str, ')');
break;
case ZEND_ARRAY_SYNTAX_SHORT:
default:
smart_str_appendc(str, '[');
zend_ast_export_list(str, zend_ast_get_list(ast), 1, 20, indent);
smart_str_appendc(str, ']');
break;
}
break;
case ZEND_AST_ENCAPS_LIST:
smart_str_appendc(str, '"');
Expand Down
37 changes: 37 additions & 0 deletions Zend/zend_builtin_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,43 @@ ZEND_FUNCTION(clone)
}
}

ZEND_FUNCTION(array)
{
zval *args;
uint32_t argc;
HashTable *named_params;

ZEND_PARSE_PARAMETERS_START(0, -1)
Z_PARAM_VARIADIC_WITH_NAMED(args, argc, named_params);
ZEND_PARSE_PARAMETERS_END();

if (EXPECTED(argc == 0)) {
if (EXPECTED(named_params != NULL)) {
GC_ADDREF(named_params);
RETURN_ARR(named_params);
} else {
RETURN_EMPTY_ARRAY();
}
} else {
HashTable *entries;

ALLOC_HASHTABLE(entries);
zend_hash_init(entries, argc + (named_params ? zend_hash_num_elements(named_params) : 0), NULL, NULL, false);
for (uint32_t i = 0; i < argc; i++) {
zend_hash_index_add_new(entries, i, &args[i]);
}
if (named_params != NULL) {
zend_string *key;
zval *val;
ZEND_HASH_FOREACH_STR_KEY_VAL(named_params, key, val) {
zend_hash_update(entries, key, val);
} ZEND_HASH_FOREACH_END();
}

RETURN_ARR(entries);
}
}

ZEND_FUNCTION(exit)
{
zend_string *str = NULL;
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_builtin_functions.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class stdClass
/** @refcount 1 */
function clone(object $object, array $withProperties = []): object {}

function _array(mixed ...$entries): array {}

function exit(string|int $status = 0): never {}

/** @alias exit */
Expand Down
8 changes: 7 additions & 1 deletion Zend/zend_builtin_functions_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Zend/zend_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,7 @@ ZEND_API zend_string *zend_type_to_string(zend_type type);
#define ZEND_ARRAY_SYNTAX_LIST 1 /* list() */
#define ZEND_ARRAY_SYNTAX_LONG 2 /* array() */
#define ZEND_ARRAY_SYNTAX_SHORT 3 /* [] */
#define ZEND_ARRAY_SYNTAX_FUNCTION 4 /* array(key: "val") */

/* var status for backpatching */
#define BP_VAR_R 0
Expand Down
21 changes: 20 additions & 1 deletion Zend/zend_language_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%type <ast> enum_declaration_statement enum_backing_type enum_case enum_case_expr
%type <ast> function_name non_empty_member_modifiers
%type <ast> property_hook property_hook_list optional_property_hook_list hooked_property property_hook_body
%type <ast> optional_parameter_list clone_argument_list non_empty_clone_argument_list
%type <ast> optional_parameter_list clone_argument_list non_empty_clone_argument_list non_empty_array_function_argument_list array_function_argument

%type <num> returns_ref function fn is_reference is_variadic property_modifiers property_hook_modifiers
%type <num> method_modifiers class_const_modifiers member_modifier optional_cpp_modifiers
Expand Down Expand Up @@ -1489,11 +1489,30 @@ ctor_arguments:

dereferenceable_scalar:
T_ARRAY '(' array_pair_list ')' { $$ = $3; $$->attr = ZEND_ARRAY_SYNTAX_LONG; }
| T_ARRAY '(' non_empty_array_function_argument_list possible_comma ')'
{ $$ = $3; $$->attr = ZEND_ARRAY_SYNTAX_FUNCTION; }
| T_ARRAY '(' T_ELLIPSIS ')' {
zend_ast *name = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_ARRAY));
name->attr = ZEND_NAME_FQ;
$$ = zend_ast_create(ZEND_AST_CALL, name, zend_ast_create_fcc());
}
| '[' array_pair_list ']' { $$ = $2; $$->attr = ZEND_ARRAY_SYNTAX_SHORT; }
| T_CONSTANT_ENCAPSED_STRING { $$ = $1; }
| '"' encaps_list '"' { $$ = $2; }
;

non_empty_array_function_argument_list:
array_function_argument
{ $$ = zend_ast_create_list(1, ZEND_AST_ARRAY, $1); }
| non_empty_array_function_argument_list ',' array_function_argument
{ $$ = zend_ast_list_add($1, $3); }
;

array_function_argument:
identifier ':' expr
{ $$ = zend_ast_create(ZEND_AST_NAMED_ARG, $1, $3); }
;

scalar:
T_LNUMBER { $$ = $1; }
| T_DNUMBER { $$ = $1; }
Expand Down
3 changes: 3 additions & 0 deletions build/gen_stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,9 @@ class FunctionName implements FunctionOrMethodName {
private /* readonly */ Name $name;

public function __construct(Name $name) {
if ($name->name === '_array') {
$name = new Name('array', $name->getAttributes());
}
$this->name = $name;
}

Expand Down
56 changes: 56 additions & 0 deletions ext/standard/tests/array/array_function.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
--TEST--
Test array() function
--FILE--
<?php
var_dump(\array(1, 2, 3));
var_dump(\array(foo: "bar", baz: "quux"));
var_dump(array(foo: "bar", baz: "quux"));

try {
assert(false && \array(foo: "bar", baz: "quux"));
} catch (AssertionError $e) {
echo $e->getMessage(), PHP_EOL;
}

var_dump(array_map(array(...), [1, 2, 3]));

?>
--EXPECT--
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
array(2) {
["foo"]=>
string(3) "bar"
["baz"]=>
string(4) "quux"
}
array(2) {
["bar"]=>
string(3) "foo"
["quux"]=>
string(3) "baz"
}
assert(false && \array(foo: 'bar', baz: 'quux'))
array(3) {
[0]=>
array(1) {
[0]=>
int(1)
}
[1]=>
array(1) {
[0]=>
int(2)
}
[2]=>
array(1) {
[0]=>
int(3)
}
}
2 changes: 0 additions & 2 deletions ext/standard/tests/array/array_map_variation16.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ $arg = [1, 2];
// built-in functions & language constructs
$callbacks = [
'echo',
'array',
'empty',
'eval',
'isset',
Expand All @@ -29,7 +28,6 @@ echo "Done";
?>
--EXPECT--
array_map(): Argument #1 ($callback) must be a valid callback or null, function "echo" not found or invalid function name
array_map(): Argument #1 ($callback) must be a valid callback or null, function "array" not found or invalid function name
array_map(): Argument #1 ($callback) must be a valid callback or null, function "empty" not found or invalid function name
array_map(): Argument #1 ($callback) must be a valid callback or null, function "eval" not found or invalid function name
array_map(): Argument #1 ($callback) must be a valid callback or null, function "isset" not found or invalid function name
Expand Down