zend_enum.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.00 of the Zend license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.zend.com/license/2_00.txt. |
  11. | If you did not receive a copy of the Zend license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@zend.com so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Ilija Tovilo <ilutov@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #include "zend.h"
  19. #include "zend_API.h"
  20. #include "zend_compile.h"
  21. #include "zend_enum_arginfo.h"
  22. #include "zend_interfaces.h"
  23. #define ZEND_ENUM_DISALLOW_MAGIC_METHOD(propertyName, methodName) \
  24. do { \
  25. if (ce->propertyName) { \
  26. zend_error_noreturn(E_COMPILE_ERROR, "Enum may not include %s", methodName); \
  27. } \
  28. } while (0);
  29. ZEND_API zend_class_entry *zend_ce_unit_enum;
  30. ZEND_API zend_class_entry *zend_ce_backed_enum;
  31. static zend_object_handlers enum_handlers;
  32. zend_object *zend_enum_new(zval *result, zend_class_entry *ce, zend_string *case_name, zval *backing_value_zv)
  33. {
  34. zend_object *zobj = zend_objects_new(ce);
  35. ZVAL_OBJ(result, zobj);
  36. ZVAL_STR_COPY(OBJ_PROP_NUM(zobj, 0), case_name);
  37. if (backing_value_zv != NULL) {
  38. ZVAL_COPY(OBJ_PROP_NUM(zobj, 1), backing_value_zv);
  39. }
  40. zobj->handlers = &enum_handlers;
  41. return zobj;
  42. }
  43. static void zend_verify_enum_properties(zend_class_entry *ce)
  44. {
  45. zend_property_info *property_info;
  46. ZEND_HASH_FOREACH_PTR(&ce->properties_info, property_info) {
  47. if (zend_string_equals_literal(property_info->name, "name")) {
  48. continue;
  49. }
  50. if (
  51. ce->enum_backing_type != IS_UNDEF
  52. && zend_string_equals_literal(property_info->name, "value")
  53. ) {
  54. continue;
  55. }
  56. // FIXME: File/line number for traits?
  57. zend_error_noreturn(E_COMPILE_ERROR, "Enum \"%s\" may not include properties",
  58. ZSTR_VAL(ce->name));
  59. } ZEND_HASH_FOREACH_END();
  60. }
  61. static void zend_verify_enum_magic_methods(zend_class_entry *ce)
  62. {
  63. // Only __get, __call and __invoke are allowed
  64. ZEND_ENUM_DISALLOW_MAGIC_METHOD(constructor, "__construct");
  65. ZEND_ENUM_DISALLOW_MAGIC_METHOD(destructor, "__destruct");
  66. ZEND_ENUM_DISALLOW_MAGIC_METHOD(clone, "__clone");
  67. ZEND_ENUM_DISALLOW_MAGIC_METHOD(__get, "__get");
  68. ZEND_ENUM_DISALLOW_MAGIC_METHOD(__set, "__set");
  69. ZEND_ENUM_DISALLOW_MAGIC_METHOD(__unset, "__unset");
  70. ZEND_ENUM_DISALLOW_MAGIC_METHOD(__isset, "__isset");
  71. ZEND_ENUM_DISALLOW_MAGIC_METHOD(__tostring, "__toString");
  72. ZEND_ENUM_DISALLOW_MAGIC_METHOD(__debugInfo, "__debugInfo");
  73. ZEND_ENUM_DISALLOW_MAGIC_METHOD(__serialize, "__serialize");
  74. ZEND_ENUM_DISALLOW_MAGIC_METHOD(__unserialize, "__unserialize");
  75. const char *forbidden_methods[] = {
  76. "__sleep",
  77. "__wakeup",
  78. "__set_state",
  79. };
  80. uint32_t forbidden_methods_length = sizeof(forbidden_methods) / sizeof(forbidden_methods[0]);
  81. for (uint32_t i = 0; i < forbidden_methods_length; ++i) {
  82. const char *forbidden_method = forbidden_methods[i];
  83. if (zend_hash_str_exists(&ce->function_table, forbidden_method, strlen(forbidden_method))) {
  84. zend_error_noreturn(E_COMPILE_ERROR, "Enum may not include magic method %s", forbidden_method);
  85. }
  86. }
  87. }
  88. static void zend_verify_enum_interfaces(zend_class_entry *ce)
  89. {
  90. if (zend_class_implements_interface(ce, zend_ce_serializable)) {
  91. zend_error_noreturn(E_COMPILE_ERROR,
  92. "Enums may not implement the Serializable interface");
  93. }
  94. }
  95. void zend_verify_enum(zend_class_entry *ce)
  96. {
  97. zend_verify_enum_properties(ce);
  98. zend_verify_enum_magic_methods(ce);
  99. zend_verify_enum_interfaces(ce);
  100. }
  101. static int zend_implement_unit_enum(zend_class_entry *interface, zend_class_entry *class_type)
  102. {
  103. if (class_type->ce_flags & ZEND_ACC_ENUM) {
  104. return SUCCESS;
  105. }
  106. zend_error_noreturn(E_ERROR, "Non-enum class %s cannot implement interface %s",
  107. ZSTR_VAL(class_type->name),
  108. ZSTR_VAL(interface->name));
  109. return FAILURE;
  110. }
  111. static int zend_implement_backed_enum(zend_class_entry *interface, zend_class_entry *class_type)
  112. {
  113. if (!(class_type->ce_flags & ZEND_ACC_ENUM)) {
  114. zend_error_noreturn(E_ERROR, "Non-enum class %s cannot implement interface %s",
  115. ZSTR_VAL(class_type->name),
  116. ZSTR_VAL(interface->name));
  117. return FAILURE;
  118. }
  119. if (class_type->enum_backing_type == IS_UNDEF) {
  120. zend_error_noreturn(E_ERROR, "Non-backed enum %s cannot implement interface %s",
  121. ZSTR_VAL(class_type->name),
  122. ZSTR_VAL(interface->name));
  123. return FAILURE;
  124. }
  125. return SUCCESS;
  126. }
  127. void zend_register_enum_ce(void)
  128. {
  129. zend_ce_unit_enum = register_class_UnitEnum();
  130. zend_ce_unit_enum->interface_gets_implemented = zend_implement_unit_enum;
  131. zend_ce_backed_enum = register_class_BackedEnum(zend_ce_unit_enum);
  132. zend_ce_backed_enum->interface_gets_implemented = zend_implement_backed_enum;
  133. memcpy(&enum_handlers, &std_object_handlers, sizeof(zend_object_handlers));
  134. enum_handlers.clone_obj = NULL;
  135. enum_handlers.compare = zend_objects_not_comparable;
  136. }
  137. void zend_enum_add_interfaces(zend_class_entry *ce)
  138. {
  139. uint32_t num_interfaces_before = ce->num_interfaces;
  140. ce->num_interfaces++;
  141. if (ce->enum_backing_type != IS_UNDEF) {
  142. ce->num_interfaces++;
  143. }
  144. ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES));
  145. ce->interface_names = erealloc(ce->interface_names, sizeof(zend_class_name) * ce->num_interfaces);
  146. ce->interface_names[num_interfaces_before].name = zend_string_copy(zend_ce_unit_enum->name);
  147. ce->interface_names[num_interfaces_before].lc_name = zend_string_init("unitenum", sizeof("unitenum") - 1, 0);
  148. if (ce->enum_backing_type != IS_UNDEF) {
  149. ce->interface_names[num_interfaces_before + 1].name = zend_string_copy(zend_ce_backed_enum->name);
  150. ce->interface_names[num_interfaces_before + 1].lc_name = zend_string_init("backedenum", sizeof("backedenum") - 1, 0);
  151. }
  152. }
  153. static ZEND_NAMED_FUNCTION(zend_enum_cases_func)
  154. {
  155. zend_class_entry *ce = execute_data->func->common.scope;
  156. zend_class_constant *c;
  157. ZEND_PARSE_PARAMETERS_NONE();
  158. array_init(return_value);
  159. ZEND_HASH_FOREACH_PTR(CE_CONSTANTS_TABLE(ce), c) {
  160. if (!(ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE)) {
  161. continue;
  162. }
  163. zval *zv = &c->value;
  164. if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
  165. if (zval_update_constant_ex(zv, c->ce) == FAILURE) {
  166. RETURN_THROWS();
  167. }
  168. }
  169. Z_ADDREF_P(zv);
  170. zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), zv);
  171. } ZEND_HASH_FOREACH_END();
  172. }
  173. static void zend_enum_from_base(INTERNAL_FUNCTION_PARAMETERS, bool try)
  174. {
  175. zend_class_entry *ce = execute_data->func->common.scope;
  176. bool release_string = false;
  177. zend_string *string_key;
  178. zend_long long_key;
  179. zval *case_name_zv;
  180. if (ce->enum_backing_type == IS_LONG) {
  181. ZEND_PARSE_PARAMETERS_START(1, 1)
  182. Z_PARAM_LONG(long_key)
  183. ZEND_PARSE_PARAMETERS_END();
  184. case_name_zv = zend_hash_index_find(ce->backed_enum_table, long_key);
  185. } else {
  186. ZEND_ASSERT(ce->enum_backing_type == IS_STRING);
  187. if (ZEND_ARG_USES_STRICT_TYPES()) {
  188. ZEND_PARSE_PARAMETERS_START(1, 1)
  189. Z_PARAM_STR(string_key)
  190. ZEND_PARSE_PARAMETERS_END();
  191. } else {
  192. // We allow long keys so that coercion to string doesn't happen implicitly. The JIT
  193. // skips deallocation of params that don't require it. In the case of from/tryFrom
  194. // passing int to from(int|string) looks like no coercion will happen, so the JIT
  195. // won't emit a dtor call. Thus we allocate/free the string manually.
  196. ZEND_PARSE_PARAMETERS_START(1, 1)
  197. Z_PARAM_STR_OR_LONG(string_key, long_key)
  198. ZEND_PARSE_PARAMETERS_END();
  199. if (string_key == NULL) {
  200. release_string = true;
  201. string_key = zend_long_to_str(long_key);
  202. }
  203. }
  204. case_name_zv = zend_hash_find(ce->backed_enum_table, string_key);
  205. }
  206. if (case_name_zv == NULL) {
  207. if (try) {
  208. goto return_null;
  209. }
  210. if (ce->enum_backing_type == IS_LONG) {
  211. zend_value_error(ZEND_LONG_FMT " is not a valid backing value for enum \"%s\"", long_key, ZSTR_VAL(ce->name));
  212. } else {
  213. ZEND_ASSERT(ce->enum_backing_type == IS_STRING);
  214. zend_value_error("\"%s\" is not a valid backing value for enum \"%s\"", ZSTR_VAL(string_key), ZSTR_VAL(ce->name));
  215. }
  216. goto throw;
  217. }
  218. // TODO: We might want to store pointers to constants in backed_enum_table instead of names,
  219. // to make this lookup more efficient.
  220. ZEND_ASSERT(Z_TYPE_P(case_name_zv) == IS_STRING);
  221. zend_class_constant *c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), Z_STR_P(case_name_zv));
  222. ZEND_ASSERT(c != NULL);
  223. zval *case_zv = &c->value;
  224. if (Z_TYPE_P(case_zv) == IS_CONSTANT_AST) {
  225. if (zval_update_constant_ex(case_zv, c->ce) == FAILURE) {
  226. goto throw;
  227. }
  228. }
  229. if (release_string) {
  230. zend_string_release(string_key);
  231. }
  232. RETURN_COPY(case_zv);
  233. throw:
  234. if (release_string) {
  235. zend_string_release(string_key);
  236. }
  237. RETURN_THROWS();
  238. return_null:
  239. if (release_string) {
  240. zend_string_release(string_key);
  241. }
  242. RETURN_NULL();
  243. }
  244. static ZEND_NAMED_FUNCTION(zend_enum_from_func)
  245. {
  246. zend_enum_from_base(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  247. }
  248. static ZEND_NAMED_FUNCTION(zend_enum_try_from_func)
  249. {
  250. zend_enum_from_base(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  251. }
  252. void zend_enum_register_funcs(zend_class_entry *ce)
  253. {
  254. const uint32_t fn_flags =
  255. ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_ARENA_ALLOCATED;
  256. zend_internal_function *cases_function =
  257. zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
  258. memset(cases_function, 0, sizeof(zend_internal_function));
  259. cases_function->type = ZEND_INTERNAL_FUNCTION;
  260. cases_function->module = EG(current_module);
  261. cases_function->handler = zend_enum_cases_func;
  262. cases_function->function_name = ZSTR_KNOWN(ZEND_STR_CASES);
  263. cases_function->scope = ce;
  264. cases_function->fn_flags = fn_flags;
  265. cases_function->arg_info = (zend_internal_arg_info *) (arginfo_class_UnitEnum_cases + 1);
  266. if (!zend_hash_add_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_CASES), cases_function)) {
  267. zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s::cases()", ZSTR_VAL(ce->name));
  268. }
  269. if (ce->enum_backing_type != IS_UNDEF) {
  270. zend_internal_function *from_function =
  271. zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
  272. memset(from_function, 0, sizeof(zend_internal_function));
  273. from_function->type = ZEND_INTERNAL_FUNCTION;
  274. from_function->module = EG(current_module);
  275. from_function->handler = zend_enum_from_func;
  276. from_function->function_name = ZSTR_KNOWN(ZEND_STR_FROM);
  277. from_function->scope = ce;
  278. from_function->fn_flags = fn_flags;
  279. from_function->num_args = 1;
  280. from_function->required_num_args = 1;
  281. from_function->arg_info = (zend_internal_arg_info *) (arginfo_class_BackedEnum_from + 1);
  282. if (!zend_hash_add_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_FROM), from_function)) {
  283. zend_error_noreturn(E_COMPILE_ERROR,
  284. "Cannot redeclare %s::from()", ZSTR_VAL(ce->name));
  285. }
  286. zend_internal_function *try_from_function =
  287. zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
  288. memset(try_from_function, 0, sizeof(zend_internal_function));
  289. try_from_function->type = ZEND_INTERNAL_FUNCTION;
  290. try_from_function->module = EG(current_module);
  291. try_from_function->handler = zend_enum_try_from_func;
  292. try_from_function->function_name = ZSTR_KNOWN(ZEND_STR_TRYFROM);
  293. try_from_function->scope = ce;
  294. try_from_function->fn_flags = fn_flags;
  295. try_from_function->num_args = 1;
  296. try_from_function->required_num_args = 1;
  297. try_from_function->arg_info = (zend_internal_arg_info *) (arginfo_class_BackedEnum_tryFrom + 1);
  298. if (!zend_hash_add_ptr(
  299. &ce->function_table, ZSTR_KNOWN(ZEND_STR_TRYFROM_LOWERCASE), try_from_function)) {
  300. zend_error_noreturn(E_COMPILE_ERROR,
  301. "Cannot redeclare %s::tryFrom()", ZSTR_VAL(ce->name));
  302. }
  303. }
  304. }
  305. void zend_enum_register_props(zend_class_entry *ce)
  306. {
  307. ce->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES;
  308. zval name_default_value;
  309. ZVAL_UNDEF(&name_default_value);
  310. zend_type name_type = ZEND_TYPE_INIT_CODE(IS_STRING, 0, 0);
  311. zend_declare_typed_property(ce, ZSTR_KNOWN(ZEND_STR_NAME), &name_default_value, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY, NULL, name_type);
  312. if (ce->enum_backing_type != IS_UNDEF) {
  313. zval value_default_value;
  314. ZVAL_UNDEF(&value_default_value);
  315. zend_type value_type = ZEND_TYPE_INIT_CODE(ce->enum_backing_type, 0, 0);
  316. zend_declare_typed_property(ce, ZSTR_KNOWN(ZEND_STR_VALUE), &value_default_value, ZEND_ACC_PUBLIC | ZEND_ACC_READONLY, NULL, value_type);
  317. }
  318. }
  319. static const zend_function_entry unit_enum_methods[] = {
  320. ZEND_NAMED_ME(cases, zend_enum_cases_func, arginfo_class_UnitEnum_cases, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
  321. ZEND_FE_END
  322. };
  323. static const zend_function_entry backed_enum_methods[] = {
  324. ZEND_NAMED_ME(cases, zend_enum_cases_func, arginfo_class_UnitEnum_cases, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
  325. ZEND_NAMED_ME(from, zend_enum_from_func, arginfo_class_BackedEnum_from, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
  326. ZEND_NAMED_ME(tryFrom, zend_enum_try_from_func, arginfo_class_BackedEnum_tryFrom, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
  327. ZEND_FE_END
  328. };
  329. ZEND_API zend_class_entry *zend_register_internal_enum(
  330. const char *name, zend_uchar type, const zend_function_entry *functions)
  331. {
  332. ZEND_ASSERT(type == IS_UNDEF || type == IS_LONG || type == IS_STRING);
  333. zend_class_entry tmp_ce;
  334. INIT_CLASS_ENTRY_EX(tmp_ce, name, strlen(name), functions);
  335. zend_class_entry *ce = zend_register_internal_class(&tmp_ce);
  336. ce->ce_flags |= ZEND_ACC_ENUM;
  337. ce->enum_backing_type = type;
  338. if (type != IS_UNDEF) {
  339. ce->backed_enum_table = pemalloc(sizeof(HashTable), 1);
  340. zend_hash_init(ce->backed_enum_table, 0, NULL, ZVAL_PTR_DTOR, 1);
  341. }
  342. zend_enum_register_props(ce);
  343. if (type == IS_UNDEF) {
  344. zend_register_functions(
  345. ce, unit_enum_methods, &ce->function_table, EG(current_module)->type);
  346. zend_class_implements(ce, 1, zend_ce_unit_enum);
  347. } else {
  348. zend_register_functions(
  349. ce, backed_enum_methods, &ce->function_table, EG(current_module)->type);
  350. zend_class_implements(ce, 1, zend_ce_backed_enum);
  351. }
  352. return ce;
  353. }
  354. static zend_ast_ref *create_enum_case_ast(
  355. zend_string *class_name, zend_string *case_name, zval *value) {
  356. // TODO: Use custom node type for enum cases?
  357. size_t size = sizeof(zend_ast_ref) + zend_ast_size(3)
  358. + (value ? 3 : 2) * sizeof(zend_ast_zval);
  359. char *p = pemalloc(size, 1);
  360. zend_ast_ref *ref = (zend_ast_ref *) p; p += sizeof(zend_ast_ref);
  361. GC_SET_REFCOUNT(ref, 1);
  362. GC_TYPE_INFO(ref) = GC_CONSTANT_AST | GC_PERSISTENT | GC_IMMUTABLE;
  363. zend_ast *ast = (zend_ast *) p; p += zend_ast_size(3);
  364. ast->kind = ZEND_AST_CONST_ENUM_INIT;
  365. ast->attr = 0;
  366. ast->lineno = 0;
  367. ast->child[0] = (zend_ast *) p; p += sizeof(zend_ast_zval);
  368. ast->child[0]->kind = ZEND_AST_ZVAL;
  369. ast->child[0]->attr = 0;
  370. ZEND_ASSERT(ZSTR_IS_INTERNED(class_name));
  371. ZVAL_STR(zend_ast_get_zval(ast->child[0]), class_name);
  372. ast->child[1] = (zend_ast *) p; p += sizeof(zend_ast_zval);
  373. ast->child[1]->kind = ZEND_AST_ZVAL;
  374. ast->child[1]->attr = 0;
  375. ZEND_ASSERT(ZSTR_IS_INTERNED(case_name));
  376. ZVAL_STR(zend_ast_get_zval(ast->child[1]), case_name);
  377. if (value) {
  378. ast->child[2] = (zend_ast *) p; p += sizeof(zend_ast_zval);
  379. ast->child[2]->kind = ZEND_AST_ZVAL;
  380. ast->child[2]->attr = 0;
  381. ZEND_ASSERT(!Z_REFCOUNTED_P(value));
  382. ZVAL_COPY_VALUE(zend_ast_get_zval(ast->child[2]), value);
  383. } else {
  384. ast->child[2] = NULL;
  385. }
  386. return ref;
  387. }
  388. ZEND_API void zend_enum_add_case(zend_class_entry *ce, zend_string *case_name, zval *value)
  389. {
  390. if (value) {
  391. ZEND_ASSERT(ce->enum_backing_type == Z_TYPE_P(value));
  392. if (Z_TYPE_P(value) == IS_STRING && !ZSTR_IS_INTERNED(Z_STR_P(value))) {
  393. zval_make_interned_string(value);
  394. }
  395. zval case_name_zv;
  396. ZVAL_STR(&case_name_zv, case_name);
  397. if (Z_TYPE_P(value) == IS_LONG) {
  398. zend_hash_index_add_new(ce->backed_enum_table, Z_LVAL_P(value), &case_name_zv);
  399. } else {
  400. zend_hash_add_new(ce->backed_enum_table, Z_STR_P(value), &case_name_zv);
  401. }
  402. } else {
  403. ZEND_ASSERT(ce->enum_backing_type == IS_UNDEF);
  404. }
  405. zval ast_zv;
  406. Z_TYPE_INFO(ast_zv) = IS_CONSTANT_AST;
  407. Z_AST(ast_zv) = create_enum_case_ast(ce->name, case_name, value);
  408. zend_class_constant *c = zend_declare_class_constant_ex(
  409. ce, case_name, &ast_zv, ZEND_ACC_PUBLIC, NULL);
  410. ZEND_CLASS_CONST_FLAGS(c) |= ZEND_CLASS_CONST_IS_CASE;
  411. }
  412. ZEND_API void zend_enum_add_case_cstr(zend_class_entry *ce, const char *name, zval *value)
  413. {
  414. zend_string *name_str = zend_string_init_interned(name, strlen(name), 1);
  415. zend_enum_add_case(ce, name_str, value);
  416. zend_string_release(name_str);
  417. }
  418. ZEND_API zend_object *zend_enum_get_case(zend_class_entry *ce, zend_string *name) {
  419. zend_class_constant *c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), name);
  420. ZEND_ASSERT(ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE);
  421. if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
  422. if (zval_update_constant_ex(&c->value, c->ce) == FAILURE) {
  423. ZEND_UNREACHABLE();
  424. }
  425. }
  426. ZEND_ASSERT(Z_TYPE(c->value) == IS_OBJECT);
  427. return Z_OBJ(c->value);
  428. }
  429. ZEND_API zend_object *zend_enum_get_case_cstr(zend_class_entry *ce, const char *name) {
  430. zend_string *name_str = zend_string_init(name, strlen(name), 0);
  431. zend_object *result = zend_enum_get_case(ce, name_str);
  432. zend_string_release(name_str);
  433. return result;
  434. }