Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ PHP NEWS
request. (ilutov)
. It is now possible to use reference assign on WeakMap without the key
needing to be present beforehand. (nielsdos)
. Added BackedEnum::values() to retrieve an indexed array of all backing
values for enum cases. (RFC: Add values() Method to BackedEnum)

- Hash:
. Upgrade xxHash to 0.8.2. (timwolla)
Expand Down
2 changes: 2 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ PHP 8.6 UPGRADE NOTES
- Core:
. It is now possible to use reference assign on WeakMap without the key
needing to be present beforehand.
. Added BackedEnum::values() static method to retrieve an indexed array of
all backing values for enum cases.

- Intl:
. Added IntlNumberRangeFormatter class to format an interval of two numbers with a given skeleton, locale, IntlNumberRangeFormatter::COLLAPSE_AUTO, IntlNumberRangeFormatter::COLLAPSE_NONE, IntlNumberRangeFormatter::COLLAPSE_UNIT, IntlNumberRangeFormatter::COLLAPSE_ALL collapse and
Expand Down
14 changes: 14 additions & 0 deletions Zend/tests/enum/backed-values-empty.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
Backed enums: values() on empty enum returns []
--FILE--
<?php

enum A: string {}

var_dump(A::values());

?>
--EXPECT--
array(0) {
}

20 changes: 20 additions & 0 deletions Zend/tests/enum/backed-values-ignore-regular-consts.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
BackedEnum::values() only returns case values, not regular constants
--FILE--
<?php
enum Mixed_: string {
case A = 'a';
case B = 'b';

public const REGULAR_CONST = 'not_a_case';
}
var_dump(Mixed_::values());
?>
--EXPECT--
array(2) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
}

24 changes: 24 additions & 0 deletions Zend/tests/enum/backed-values-int.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
Backed enums: values() returns ints
--FILE--
<?php

enum Priority: int {
case Low = 1;
case Medium = 5;
case High = 10;
}

var_dump(Priority::values());

?>
--EXPECT--
array(3) {
[0]=>
int(1)
[1]=>
int(5)
[2]=>
int(10)
}

15 changes: 15 additions & 0 deletions Zend/tests/enum/backed-values-not-on-pure.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Unit enums do not have values()
--FILE--
<?php

enum U {
case A;
}

var_dump(method_exists(U::class, 'values'));

?>
--EXPECT--
bool(false)

21 changes: 21 additions & 0 deletions Zend/tests/enum/backed-values-order.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
BackedEnum::values() preserves declaration order
--FILE--
<?php
enum Order: int {
case Third = 3;
case First = 1;
case Second = 2;
}
var_dump(Order::values());
?>
--EXPECT--
array(3) {
[0]=>
int(3)
[1]=>
int(1)
[2]=>
int(2)
}

24 changes: 24 additions & 0 deletions Zend/tests/enum/backed-values-string.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
Backed enums: values() returns strings
--FILE--
<?php

enum Color: string {
case Red = 'red';
case Green = 'green';
case Blue = 'blue';
}

var_dump(Color::values());

?>
--EXPECT--
array(3) {
[0]=>
string(3) "red"
[1]=>
string(5) "green"
[2]=>
string(4) "blue"
}

46 changes: 41 additions & 5 deletions Zend/zend_enum.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,9 +410,34 @@ static ZEND_NAMED_FUNCTION(zend_enum_from_func)

static ZEND_NAMED_FUNCTION(zend_enum_try_from_func)
{
zend_enum_from_base(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
zend_enum_from_base(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}

static ZEND_NAMED_FUNCTION(zend_enum_values_func)
{
zend_class_entry *ce = execute_data->func->common.scope;
zend_class_constant *c;

ZEND_PARSE_PARAMETERS_NONE();

array_init(return_value);

ZEND_HASH_MAP_FOREACH_PTR(CE_CONSTANTS_TABLE(ce), c) {
if (!(ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE)) {
continue;
}
zval *zv = &c->value;
if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
if (zval_update_constant_ex(zv, c->ce) == FAILURE) {
RETURN_THROWS();
}
}
zval *prop = zend_enum_fetch_case_value(Z_OBJ_P(zv));
zval tmp;
ZVAL_COPY(&tmp, prop);
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
} ZEND_HASH_FOREACH_END();
}
static void zend_enum_register_func(zend_class_entry *ce, zend_known_string_id name_id, zend_internal_function *zif) {
zend_string *name = ZSTR_KNOWN(name_id);
zif->type = ZEND_INTERNAL_FUNCTION;
Expand Down Expand Up @@ -469,6 +494,16 @@ void zend_enum_register_funcs(zend_class_entry *ce)
try_from_function->required_num_args = 1;
try_from_function->arg_info = (zend_internal_arg_info *) (arginfo_class_BackedEnum_tryFrom + 1);
zend_enum_register_func(ce, ZEND_STR_TRYFROM_LOWERCASE, try_from_function);

zend_internal_function *values_function = zend_arena_calloc(&CG(arena), sizeof(zend_internal_function), 1);
values_function->handler = zend_enum_values_func;
values_function->function_name = ZSTR_KNOWN(ZEND_STR_VALUES);
values_function->fn_flags = fn_flags;
values_function->doc_comment = NULL;
values_function->num_args = 0;
values_function->required_num_args = 0;
values_function->arg_info = (zend_internal_arg_info *) (arginfo_class_BackedEnum_values + 1);
zend_enum_register_func(ce, ZEND_STR_VALUES, values_function);
}
}

Expand All @@ -495,10 +530,11 @@ static const zend_function_entry unit_enum_methods[] = {
};

static const zend_function_entry backed_enum_methods[] = {
ZEND_NAMED_ME(cases, zend_enum_cases_func, arginfo_class_UnitEnum_cases, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_NAMED_ME(from, zend_enum_from_func, arginfo_class_BackedEnum_from, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_NAMED_ME(tryFrom, zend_enum_try_from_func, arginfo_class_BackedEnum_tryFrom, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
ZEND_NAMED_ME(cases, zend_enum_cases_func, arginfo_class_UnitEnum_cases, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_NAMED_ME(from, zend_enum_from_func, arginfo_class_BackedEnum_from, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_NAMED_ME(tryFrom, zend_enum_try_from_func, arginfo_class_BackedEnum_tryFrom, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_NAMED_ME(values, zend_enum_values_func, arginfo_class_BackedEnum_values, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
ZEND_FE_END
};

ZEND_API zend_class_entry *zend_register_internal_enum(
Expand Down
7 changes: 7 additions & 0 deletions Zend/zend_enum.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,11 @@ interface BackedEnum extends UnitEnum
public static function from(int|string $value): static;

public static function tryFrom(int|string $value): ?static;

/**
* Returns an indexed array of all backing values for the enum cases.
*
* @return int[]|string[]
*/
public static function values(): array;
}
5 changes: 4 additions & 1 deletion Zend/zend_enum_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_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ EMPTY_SWITCH_DEFAULT_CASE()
_(ZEND_STR_CASES, "cases") \
_(ZEND_STR_FROM, "from") \
_(ZEND_STR_TRYFROM, "tryFrom") \
_(ZEND_STR_VALUES, "values") \
_(ZEND_STR_TRYFROM_LOWERCASE, "tryfrom") \
_(ZEND_STR_AUTOGLOBAL_SERVER, "_SERVER") \
_(ZEND_STR_AUTOGLOBAL_ENV, "_ENV") \
Expand Down
17 changes: 17 additions & 0 deletions ext/reflection/tests/BackedEnum_values_reflection.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
BackedEnum::values() appears in reflection
--FILE--
<?php
enum Status: string {
case Active = 'active';
}
$method = new ReflectionMethod(Status::class, 'values');
var_dump($method->isStatic());
var_dump($method->isPublic());
var_dump($method->getNumberOfParameters());
?>
--EXPECT--
bool(true)
bool(true)
int(0)

18 changes: 16 additions & 2 deletions ext/reflection/tests/ReflectionEnum_toString_backed_int.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Enum [ <user> enum MyBool: int implements MyStringable, UnitEnum, BackedEnum ] {
- Static properties [0] {
}

- Static methods [3] {
- Static methods [4] {
Method [ <internal, prototype UnitEnum> static public method cases ] {

- Parameters [0] {
Expand All @@ -66,6 +66,13 @@ Enum [ <user> enum MyBool: int implements MyStringable, UnitEnum, BackedEnum ] {
}
- Return [ ?static ]
}

Method [ <internal, prototype BackedEnum> static public method values ] {

- Parameters [0] {
}
- Return [ array ]
}
}

- Properties [2] {
Expand Down Expand Up @@ -99,7 +106,7 @@ Enum [ <user> enum MyBool: int implements MyStringable, UnitEnum, BackedEnum ] {
- Static properties [0] {
}

- Static methods [3] {
- Static methods [4] {
Method [ <internal, prototype UnitEnum> static public method cases ] {

- Parameters [0] {
Expand All @@ -122,6 +129,13 @@ Enum [ <user> enum MyBool: int implements MyStringable, UnitEnum, BackedEnum ] {
}
- Return [ ?static ]
}

Method [ <internal, prototype BackedEnum> static public method values ] {

- Parameters [0] {
}
- Return [ array ]
}
}

- Properties [2] {
Expand Down
18 changes: 16 additions & 2 deletions ext/reflection/tests/ReflectionEnum_toString_backed_string.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Enum [ <user> enum MyBool: string implements MyStringable, UnitEnum, BackedEnum
- Static properties [0] {
}

- Static methods [3] {
- Static methods [4] {
Method [ <internal, prototype UnitEnum> static public method cases ] {

- Parameters [0] {
Expand All @@ -66,6 +66,13 @@ Enum [ <user> enum MyBool: string implements MyStringable, UnitEnum, BackedEnum
}
- Return [ ?static ]
}

Method [ <internal, prototype BackedEnum> static public method values ] {

- Parameters [0] {
}
- Return [ array ]
}
}

- Properties [2] {
Expand Down Expand Up @@ -99,7 +106,7 @@ Enum [ <user> enum MyBool: string implements MyStringable, UnitEnum, BackedEnum
- Static properties [0] {
}

- Static methods [3] {
- Static methods [4] {
Method [ <internal, prototype UnitEnum> static public method cases ] {

- Parameters [0] {
Expand All @@ -122,6 +129,13 @@ Enum [ <user> enum MyBool: string implements MyStringable, UnitEnum, BackedEnum
}
- Return [ ?static ]
}

Method [ <internal, prototype BackedEnum> static public method values ] {

- Parameters [0] {
}
- Return [ array ]
}
}

- Properties [2] {
Expand Down