}
/* }}} */
+uint32_t zend_get_class_fetch_type(zend_string *name) /* {{{ */
+{
+ if (zend_string_equals_literal_ci(name, "self")) {
+ return ZEND_FETCH_CLASS_SELF;
+ } else if (zend_string_equals_literal_ci(name, "parent")) {
+ return ZEND_FETCH_CLASS_PARENT;
+ } else if (zend_string_equals_literal_ci(name, "static")) {
+ return ZEND_FETCH_CLASS_STATIC;
+ } else {
+ return ZEND_FETCH_CLASS_DEFAULT;
+ }
+}
+/* }}} */
+
+static uint32_t zend_get_class_fetch_type_ast(zend_ast *name_ast) /* {{{ */
+{
+ /* Fully qualified names are always default refs */
+ if (name_ast->attr == ZEND_NAME_FQ) {
+ return ZEND_FETCH_CLASS_DEFAULT;
+ }
+
+ return zend_get_class_fetch_type(zend_ast_get_str(name_ast));
+}
+/* }}} */
+
+static void zend_ensure_valid_class_fetch_type(uint32_t fetch_type) /* {{{ */
+{
+ if (fetch_type != ZEND_FETCH_CLASS_DEFAULT && !CG(active_class_entry) && zend_is_scope_known()) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"%s\" when no class scope is active",
+ fetch_type == ZEND_FETCH_CLASS_SELF ? "self" :
+ fetch_type == ZEND_FETCH_CLASS_PARENT ? "parent" : "static");
+ }
+}
+/* }}} */
+
+static zend_bool zend_try_compile_const_expr_resolve_class_name(zval *zv, zend_ast *class_ast, zend_ast *name_ast, zend_bool constant) /* {{{ */
+{
+ uint32_t fetch_type;
+
+ if (name_ast->kind != ZEND_AST_ZVAL) {
+ return 0;
+ }
+
+ if (!zend_string_equals_literal_ci(zend_ast_get_str(name_ast), "class")) {
+ return 0;
+ }
+
+ if (class_ast->kind != ZEND_AST_ZVAL) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Dynamic class names are not allowed in compile-time ::class fetch");
+ }
+
+ fetch_type = zend_get_class_fetch_type(zend_ast_get_str(class_ast));
+ zend_ensure_valid_class_fetch_type(fetch_type);
+
+ switch (fetch_type) {
+ case ZEND_FETCH_CLASS_SELF:
+ if (constant || (CG(active_class_entry) && zend_is_scope_known())) {
+ ZVAL_STR_COPY(zv, CG(active_class_entry)->name);
+ } else {
+ ZVAL_NULL(zv);
+ }
+ return 1;
+ case ZEND_FETCH_CLASS_STATIC:
+ case ZEND_FETCH_CLASS_PARENT:
+ if (constant) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "%s::class cannot be used for compile-time class name resolution",
+ fetch_type == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
+ );
+ } else {
+ ZVAL_NULL(zv);
+ }
+ return 1;
+ case ZEND_FETCH_CLASS_DEFAULT:
+ ZVAL_STR(zv, zend_resolve_class_name_ast(class_ast));
+ return 1;
+ EMPTY_SWITCH_DEFAULT_CASE()
+ }
+}
+/* }}} */
+
static zend_bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend_string *name) /* {{{ */
{
uint32_t fetch_type = zend_get_class_fetch_type(class_name);
}
/* }}} */
-uint32_t zend_get_class_fetch_type(zend_string *name) /* {{{ */
-{
- if (zend_string_equals_literal_ci(name, "self")) {
- return ZEND_FETCH_CLASS_SELF;
- } else if (zend_string_equals_literal_ci(name, "parent")) {
- return ZEND_FETCH_CLASS_PARENT;
- } else if (zend_string_equals_literal_ci(name, "static")) {
- return ZEND_FETCH_CLASS_STATIC;
- } else {
- return ZEND_FETCH_CLASS_DEFAULT;
- }
-}
-/* }}} */
-
-static uint32_t zend_get_class_fetch_type_ast(zend_ast *name_ast) /* {{{ */
-{
- /* Fully qualified names are always default refs */
- if (name_ast->attr == ZEND_NAME_FQ) {
- return ZEND_FETCH_CLASS_DEFAULT;
- }
-
- return zend_get_class_fetch_type(zend_ast_get_str(name_ast));
-}
-/* }}} */
-
-static void zend_ensure_valid_class_fetch_type(uint32_t fetch_type) /* {{{ */
-{
- if (fetch_type != ZEND_FETCH_CLASS_DEFAULT && !CG(active_class_entry) && zend_is_scope_known()) {
- zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"%s\" when no class scope is active",
- fetch_type == ZEND_FETCH_CLASS_SELF ? "self" :
- fetch_type == ZEND_FETCH_CLASS_PARENT ? "parent" : "static");
- }
-}
-/* }}} */
-
ZEND_API zend_string *zend_get_compiled_variable_name(const zend_op_array *op_array, uint32_t var) /* {{{ */
{
return op_array->vars[EX_VAR_TO_NUM(var)];
zend_string *name = zend_ast_get_str(name_ast);
zval value_zv;
+ if (zend_string_equals_literal_ci(name, "class")) {
+ zend_error(E_COMPILE_ERROR,
+ "A class constant must not be called 'class'; it is reserved for class name fetching");
+ }
+
zend_const_expr_to_zval(&value_zv, value_ast);
name = zend_new_interned_string_safe(name);
zend_op *opline;
zend_string *resolved_name;
+ if (zend_try_compile_const_expr_resolve_class_name(&result->u.constant, class_ast, const_ast, 0)) {
+ if (Z_TYPE(result->u.constant) == IS_NULL) {
+ zend_op *opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, NULL, NULL);
+ opline->extended_value = zend_get_class_fetch_type(zend_ast_get_str(class_ast));
+ } else {
+ result->op_type = IS_CONST;
+ }
+ return;
+ }
+
zend_eval_const_expr(&class_ast);
zend_eval_const_expr(&const_ast);
return;
}
}
+ if (const_ast->kind == ZEND_AST_ZVAL && zend_string_equals_literal_ci(zend_ast_get_str(const_ast), "class")) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Dynamic class names are not allowed in compile-time ::class fetch");
+ }
if (zend_is_const_default_class_ref(class_ast)) {
class_node.op_type = IS_CONST;
|| kind == ZEND_AST_CONDITIONAL || kind == ZEND_AST_DIM
|| kind == ZEND_AST_ARRAY || kind == ZEND_AST_ARRAY_ELEM
|| kind == ZEND_AST_CONST || kind == ZEND_AST_CLASS_CONST
- || kind == ZEND_AST_RESOLVE_CLASS_NAME || kind == ZEND_AST_MAGIC_CONST;
+ || kind == ZEND_AST_MAGIC_CONST;
}
/* }}} */
"Dynamic class names are not allowed in compile-time class constant references");
}
+ if (zend_try_compile_const_expr_resolve_class_name(&result, class_ast, const_ast, 1)) {
+ *ast_ptr = zend_ast_create_zval(&result);
+ return;
+ }
+
class_name = zend_ast_get_str(class_ast);
fetch_type = zend_get_class_fetch_type(class_name);
}
/* }}} */
-void zend_compile_const_expr_resolve_class_name(zend_ast **ast_ptr) /* {{{ */
-{
- zend_ast *ast = *ast_ptr;
- zend_ast *name_ast = ast->child[0];
- zval result;
- uint32_t fetch_type = zend_get_class_fetch_type(zend_ast_get_str(name_ast));
- zend_ensure_valid_class_fetch_type(fetch_type);
-
- switch (fetch_type) {
- case ZEND_FETCH_CLASS_SELF:
- ZVAL_STR_COPY(&result, CG(active_class_entry)->name);
- break;
- case ZEND_FETCH_CLASS_STATIC:
- case ZEND_FETCH_CLASS_PARENT:
- zend_error_noreturn(E_COMPILE_ERROR,
- "%s::class cannot be used for compile-time class name resolution",
- fetch_type == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
- );
- break;
- case ZEND_FETCH_CLASS_DEFAULT:
- ZVAL_STR(&result, zend_resolve_class_name_ast(name_ast));
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
-
- zend_ast_destroy(ast);
- *ast_ptr = zend_ast_create_zval(&result);
-}
-/* }}} */
-
void zend_compile_const_expr_magic_const(zend_ast **ast_ptr) /* {{{ */
{
zend_ast *ast = *ast_ptr;
case ZEND_AST_CONST:
zend_compile_const_expr_const(ast_ptr);
break;
- case ZEND_AST_RESOLVE_CLASS_NAME:
- zend_compile_const_expr_resolve_class_name(ast_ptr);
- break;
case ZEND_AST_MAGIC_CONST:
zend_compile_const_expr_magic_const(ast_ptr);
break;
case ZEND_AST_CLASS_CONST:
zend_compile_class_const(result, ast);
return;
- case ZEND_AST_RESOLVE_CLASS_NAME:
- zend_compile_resolve_class_name(result, ast);
- return;
case ZEND_AST_ENCAPS_LIST:
zend_compile_encaps_list(result, ast);
return;
zend_ast *name_ast = ast->child[1];
zend_string *resolved_name;
+ if (zend_try_compile_const_expr_resolve_class_name(&result, class_ast, name_ast, 1)) {
+ break;
+ }
+
zend_eval_const_expr(&class_ast);
zend_eval_const_expr(&name_ast);
+ if (name_ast->kind == ZEND_AST_ZVAL && zend_string_equals_literal_ci(zend_ast_get_str(name_ast), "class")) {
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Dynamic class names are not allowed in compile-time ::class fetch");
+ }
+
if (class_ast->kind != ZEND_AST_ZVAL || name_ast->kind != ZEND_AST_ZVAL) {
return;
}
*/
PHPAPI void php_implode(const zend_string *delim, zval *arr, zval *return_value)
{
- zval *tmp;
- smart_str implstr = {0};
- int numelems, i = 0;
- zend_string *str;
+ zval *tmp;
+ int numelems;
+ zend_string *str;
+ char *cptr;
+ size_t len = 0;
+ zend_string **strings, **strptr;
numelems = zend_hash_num_elements(Z_ARRVAL_P(arr));
if (numelems == 0) {
RETURN_EMPTY_STRING();
+ } else if (numelems == 1) {
+ /* loop to search the first not undefined element... */
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), tmp) {
+ RETURN_STR(zval_get_string(tmp));
+ } ZEND_HASH_FOREACH_END();
}
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), tmp) {
-again:
- switch (Z_TYPE_P(tmp)) {
- case IS_STRING:
- smart_str_append(&implstr, Z_STR_P(tmp));
- break;
-
- case IS_LONG:
- smart_str_append_long(&implstr, Z_LVAL_P(tmp));
- break;
-
- case IS_TRUE:
- smart_str_appendl(&implstr, "1", sizeof("1")-1);
- break;
-
- case IS_NULL:
- case IS_FALSE:
- break;
-
- case IS_DOUBLE: {
- char *stmp;
- size_t str_len = spprintf(&stmp, 0, "%.*G", (int) EG(precision), Z_DVAL_P(tmp));
- smart_str_appendl(&implstr, stmp, str_len);
- efree(stmp);
- break;
- }
-
- case IS_REFERENCE:
- tmp = Z_REFVAL_P(tmp);
- goto again;
-
- default:
- str = zval_get_string(tmp);
- smart_str_append(&implstr, str);
- zend_string_release(str);
- break;
-
- }
+ strings = emalloc(sizeof(zend_string *) * numelems);
+ strptr = strings - 1;
- if (++i != numelems) {
- smart_str_append(&implstr, delim);
- }
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), tmp) {
+ *++strptr = zval_get_string(tmp);
+ len += (*strptr)->len;
} ZEND_HASH_FOREACH_END();
- smart_str_0(&implstr);
+ str = zend_string_alloc(len + (numelems - 1) * delim->len, 0);
+ cptr = str->val + str->len;
+ *cptr = 0;
- if (implstr.s) {
- RETURN_NEW_STR(implstr.s);
- } else {
- smart_str_free(&implstr);
- RETURN_EMPTY_STRING();
- }
+ do {
+ cptr -= (*strptr)->len;
+ memcpy(cptr, (*strptr)->val, (*strptr)->len);
+ zend_string_release(*strptr);
+
+ cptr -= delim->len;
+ memcpy(cptr, delim->val, delim->len);
+ } while (--strptr > strings);
+ memcpy(str->val, (*strptr)->val, (*strptr)->len);
+ zend_string_release(*strptr);
+
+ efree(strings);
+ RETURN_NEW_STR(str);
}
/* }}} */