summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@php.net>2007-08-24 13:50:52 +0000
committerDmitry Stogov <dmitry@php.net>2007-08-24 13:50:52 +0000
commit611abb17fc380193e4b0c0cc179dbfa78afb5ce2 (patch)
tree5cbe30b2d9a748155ead1fa500fa139cae42a209
parent41bda78bd245ad7bdad2ca2feb71d5260fb487a8 (diff)
downloadphp-git-611abb17fc380193e4b0c0cc179dbfa78afb5ce2.tar.gz
Namespace constants
-rwxr-xr-xZend/tests/bug41633_2.phpt2
-rw-r--r--Zend/tests/ns_039.phpt23
-rw-r--r--Zend/tests/ns_040.phpt68
-rw-r--r--Zend/tests/ns_041.phpt22
-rw-r--r--Zend/tests/ns_042.phpt22
-rw-r--r--Zend/tests/ns_043.phpt11
-rw-r--r--Zend/tests/ns_044.phpt9
-rw-r--r--Zend/tests/ns_045.phpt11
-rw-r--r--Zend/tests/ns_046.phpt11
-rw-r--r--Zend/tests/ns_047.phpt11
-rw-r--r--Zend/tests/ns_048.phpt11
-rw-r--r--Zend/tests/ns_049.phpt9
-rw-r--r--Zend/tests/ns_050.phpt14
-rw-r--r--Zend/tests/ns_051.phpt12
-rw-r--r--Zend/tests/ns_052.phpt14
-rw-r--r--Zend/tests/ns_053.phpt13
-rw-r--r--Zend/zend.c4
-rw-r--r--Zend/zend.h4
-rw-r--r--Zend/zend_builtin_functions.c4
-rw-r--r--Zend/zend_compile.c136
-rw-r--r--Zend/zend_compile.h3
-rw-r--r--Zend/zend_constants.c191
-rw-r--r--Zend/zend_constants.h3
-rw-r--r--Zend/zend_execute_API.c18
-rw-r--r--Zend/zend_language_parser.y17
-rw-r--r--Zend/zend_variables.c6
-rw-r--r--Zend/zend_vm_def.h93
-rw-r--r--Zend/zend_vm_execute.h205
-rw-r--r--Zend/zend_vm_opcodes.h1
-rw-r--r--ext/standard/basic_functions.c2
30 files changed, 800 insertions, 150 deletions
diff --git a/Zend/tests/bug41633_2.phpt b/Zend/tests/bug41633_2.phpt
index 3deb4516ac..23c0e6b649 100755
--- a/Zend/tests/bug41633_2.phpt
+++ b/Zend/tests/bug41633_2.phpt
@@ -8,4 +8,4 @@ class Foo {
echo Foo::A."\n";
?>
--EXPECTF--
-Fatal error: Undefined class constant 'self::B' in %sbug41633_2.php on line 5
+Fatal error: Undefined class constant 'B' in %sbug41633_2.php on line 5
diff --git a/Zend/tests/ns_039.phpt b/Zend/tests/ns_039.phpt
new file mode 100644
index 0000000000..95fae8fc01
--- /dev/null
+++ b/Zend/tests/ns_039.phpt
@@ -0,0 +1,23 @@
+--TEST--
+039: Constant declaration
+--FILE--
+<?php
+const A = "ok";
+const B = A;
+const C = array("ok");
+const D = array(B);
+echo A . "\n";
+echo B . "\n";
+print_r(C);
+print_r(D);
+--EXPECT--
+ok
+ok
+Array
+(
+ [0] => ok
+)
+Array
+(
+ [0] => ok
+)
diff --git a/Zend/tests/ns_040.phpt b/Zend/tests/ns_040.phpt
new file mode 100644
index 0000000000..11799f9a73
--- /dev/null
+++ b/Zend/tests/ns_040.phpt
@@ -0,0 +1,68 @@
+--TEST--
+040: Constant declaration and usage in namespace
+--FILE--
+<?php
+namespace X;
+import X as Y;
+const A = "ok\n";
+const B = A;
+const C = array(A);
+const D = array("aaa"=>A);
+const E = array(A=>"aaa\n");
+function f1($x=A) {
+ echo $x;
+}
+function f2($x=X::A) {
+ echo $x;
+}
+function f3($x=Y::A) {
+ echo $x;
+}
+function f4($x=::X::A) {
+ echo $x;
+}
+function f5($x=B) {
+ echo $x;
+}
+function f6($x=array(A)) {
+ echo $x[0];
+}
+function f7($x=array("aaa"=>A)) {
+ echo $x["aaa"];
+}
+function f8($x=array(A=>"aaa\n")) {
+ echo $x["ok\n"];
+}
+echo A;
+echo X::A;
+echo Y::A;
+echo ::X::A;
+f1();
+f2();
+f3();
+f4();
+echo B;
+$x = C; echo $x[0];
+$x = D; echo $x["aaa"];
+$x = E; echo $x["ok\n"];
+f5();
+f6();
+f7();
+f8();
+--EXPECT--
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+aaa
+ok
+ok
+ok
+aaa
diff --git a/Zend/tests/ns_041.phpt b/Zend/tests/ns_041.phpt
new file mode 100644
index 0000000000..889f3d82c9
--- /dev/null
+++ b/Zend/tests/ns_041.phpt
@@ -0,0 +1,22 @@
+--TEST--
+041: Constants in namespace
+--FILE--
+<?php
+namespace test::ns1;
+
+const FOO = "ok\n";
+
+echo(FOO);
+echo(test::ns1::FOO);
+echo(::test::ns1::FOO);
+echo(BAR);
+
+const BAR = "ok\n";
+
+--EXPECTF--
+ok
+ok
+ok
+
+Notice: Use of undefined constant BAR - assumed 'BAR' in %sns_041.php on line 9
+BAR
diff --git a/Zend/tests/ns_042.phpt b/Zend/tests/ns_042.phpt
new file mode 100644
index 0000000000..bda697bff9
--- /dev/null
+++ b/Zend/tests/ns_042.phpt
@@ -0,0 +1,22 @@
+--TEST--
+042: Import in namespace and constants
+--FILE--
+<?php
+namespace test::ns1;
+
+const FOO = "ok\n";
+
+import test::ns1 as ns2;
+import test as ns3;
+
+echo FOO;
+echo test::ns1::FOO;
+echo ::test::ns1::FOO;
+echo ns2::FOO;
+echo ns3::ns1::FOO;
+--EXPECT--
+ok
+ok
+ok
+ok
+ok
diff --git a/Zend/tests/ns_043.phpt b/Zend/tests/ns_043.phpt
new file mode 100644
index 0000000000..63bd05eaaf
--- /dev/null
+++ b/Zend/tests/ns_043.phpt
@@ -0,0 +1,11 @@
+--TEST--
+043: Name conflict and constants (ns name)
+--FILE--
+<?php
+namespace test::ns1;
+
+const INI_ALL = 0;
+
+var_dump(INI_ALL);
+--EXPECT--
+int(0)
diff --git a/Zend/tests/ns_044.phpt b/Zend/tests/ns_044.phpt
new file mode 100644
index 0000000000..d379b97a24
--- /dev/null
+++ b/Zend/tests/ns_044.phpt
@@ -0,0 +1,9 @@
+--TEST--
+044: Name conflict and constants (php name)
+--FILE--
+<?php
+namespace test::ns1;
+
+var_dump(INI_ALL);
+--EXPECT--
+int(7)
diff --git a/Zend/tests/ns_045.phpt b/Zend/tests/ns_045.phpt
new file mode 100644
index 0000000000..d8c942948e
--- /dev/null
+++ b/Zend/tests/ns_045.phpt
@@ -0,0 +1,11 @@
+--TEST--
+045: Name conflict and constants (php name in case if ns name exists)
+--FILE--
+<?php
+namespace test::ns1;
+
+const INI_ALL = 0;
+
+var_dump(::INI_ALL);
+--EXPECT--
+int(7)
diff --git a/Zend/tests/ns_046.phpt b/Zend/tests/ns_046.phpt
new file mode 100644
index 0000000000..e48f0cef24
--- /dev/null
+++ b/Zend/tests/ns_046.phpt
@@ -0,0 +1,11 @@
+--TEST--
+046: Run-time name conflict and constants (ns name)
+--FILE--
+<?php
+namespace test::ns1;
+
+const INI_ALL = 0;
+
+var_dump(constant("test::ns1::INI_ALL"));
+--EXPECT--
+int(0)
diff --git a/Zend/tests/ns_047.phpt b/Zend/tests/ns_047.phpt
new file mode 100644
index 0000000000..89795da256
--- /dev/null
+++ b/Zend/tests/ns_047.phpt
@@ -0,0 +1,11 @@
+--TEST--
+047: Run-time name conflict and constants (php name)
+--FILE--
+<?php
+namespace test::ns1;
+
+const INI_ALL = 0;
+
+var_dump(constant("INI_ALL"));
+--EXPECT--
+int(7)
diff --git a/Zend/tests/ns_048.phpt b/Zend/tests/ns_048.phpt
new file mode 100644
index 0000000000..3837643cf2
--- /dev/null
+++ b/Zend/tests/ns_048.phpt
@@ -0,0 +1,11 @@
+--TEST--
+048: __NAMESPACE__ constant and runtime names (ns name)
+--FILE--
+<?php
+namespace test::ns1;
+
+const FOO = 0;
+
+var_dump(constant(__NAMESPACE__ . "::FOO"));
+--EXPECT--
+int(0)
diff --git a/Zend/tests/ns_049.phpt b/Zend/tests/ns_049.phpt
new file mode 100644
index 0000000000..3e5ccc6783
--- /dev/null
+++ b/Zend/tests/ns_049.phpt
@@ -0,0 +1,9 @@
+--TEST--
+049: __NAMESPACE__ constant and runtime names (php name)
+--FILE--
+<?php
+const FOO = 0;
+
+var_dump(constant(__NAMESPACE__ . "::FOO"));
+--EXPECT--
+int(0)
diff --git a/Zend/tests/ns_050.phpt b/Zend/tests/ns_050.phpt
new file mode 100644
index 0000000000..9171f6c4b1
--- /dev/null
+++ b/Zend/tests/ns_050.phpt
@@ -0,0 +1,14 @@
+--TEST--
+050: Name conflict and compile-time constants (ns name)
+--FILE--
+<?php
+namespace test::ns1;
+
+const INI_ALL = 0;
+
+function foo($x = INI_ALL) {
+ var_dump($x);
+}
+foo();
+--EXPECT--
+int(0)
diff --git a/Zend/tests/ns_051.phpt b/Zend/tests/ns_051.phpt
new file mode 100644
index 0000000000..07985ba106
--- /dev/null
+++ b/Zend/tests/ns_051.phpt
@@ -0,0 +1,12 @@
+--TEST--
+051: Name conflict and compile-time constants (php name)
+--FILE--
+<?php
+namespace test::ns1;
+
+function foo($x = INI_ALL) {
+ var_dump($x);
+}
+foo();
+--EXPECT--
+int(7)
diff --git a/Zend/tests/ns_052.phpt b/Zend/tests/ns_052.phpt
new file mode 100644
index 0000000000..1f2c4a073f
--- /dev/null
+++ b/Zend/tests/ns_052.phpt
@@ -0,0 +1,14 @@
+--TEST--
+052: Name conflict and compile-time constants (php name in case if ns name exists)
+--FILE--
+<?php
+namespace test::ns1;
+
+const INI_ALL = 0;
+
+function foo($x = ::INI_ALL) {
+ var_dump($x);
+}
+foo();
+--EXPECT--
+int(7)
diff --git a/Zend/tests/ns_053.phpt b/Zend/tests/ns_053.phpt
new file mode 100644
index 0000000000..8df545face
--- /dev/null
+++ b/Zend/tests/ns_053.phpt
@@ -0,0 +1,13 @@
+--TEST--
+053: Run-time constant definition
+--FILE--
+<?php
+namespace test::ns1;
+
+define(__NAMESPACE__ . '::NAME', basename(__FILE__));
+echo NAME."\n";
+echo test::ns1::NAME."\n";
+--EXPECT--
+ns_053.php
+ns_053.php
+
diff --git a/Zend/zend.c b/Zend/zend.c
index ea9af02128..76651bc5b1 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -696,7 +696,7 @@ static void zend_set_default_compile_time_values(TSRMLS_D) /* {{{ */
static void zval_copy_persistent(zval *zv) /* {{{ */
{
- if (Z_TYPE_P(zv) == IS_STRING || Z_TYPE_P(zv) == IS_CONSTANT) {
+ if (Z_TYPE_P(zv) == IS_STRING || (Z_TYPE_P(zv) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) {
UChar *ustr;
ustr = malloc(UBYTES(Z_STRLEN_P(zv)+1));
@@ -783,7 +783,7 @@ static void const_to_unicode(zend_constant *c) /* {{{ */
free(c->name.s);
c->name.u = uname;
}
- if (Z_TYPE(c->value) == IS_STRING || Z_TYPE(c->value) == IS_CONSTANT) {
+ if (Z_TYPE(c->value) == IS_STRING || (Z_TYPE(c->value) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) {
UChar *ustr;
ustr = malloc(UBYTES(Z_STRLEN(c->value)+1));
diff --git a/Zend/zend.h b/Zend/zend.h
index f503199fb5..08b6b04670 100644
--- a/Zend/zend.h
+++ b/Zend/zend.h
@@ -467,7 +467,9 @@ typedef int (*zend_write_func_t)(const char *str, uint str_length);
#define IS_UNICODE 10
/* Ugly hack to support constants as static array indices */
-#define IS_CONSTANT_INDEX 0x80
+#define IS_CONSTANT_TYPE_MASK 0x0f
+#define IS_CONSTANT_RT_NS_CHECK 0x10
+#define IS_CONSTANT_INDEX 0x80
/* overloaded elements data types */
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index e5e6bdb878..1788cede60 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -575,7 +575,7 @@ ZEND_FUNCTION(defined)
}
convert_to_text_ex(var);
- if (zend_u_get_constant(Z_TYPE_PP(var), Z_UNIVAL_PP(var), Z_UNILEN_PP(var), &c, NULL TSRMLS_CC)) {
+ if (zend_u_get_constant_ex(Z_TYPE_PP(var), Z_UNIVAL_PP(var), Z_UNILEN_PP(var), &c, NULL, 0 TSRMLS_CC)) {
zval_dtor(&c);
RETURN_TRUE;
} else {
@@ -772,7 +772,7 @@ static void add_class_vars(zend_class_entry *ce, HashTable *properties, zval *re
/* this is necessary to make it able to work with default array
* properties, returned to user */
- if (Z_TYPE_P(prop_copy) == IS_CONSTANT_ARRAY || Z_TYPE_P(prop_copy) == IS_CONSTANT) {
+ if (Z_TYPE_P(prop_copy) == IS_CONSTANT_ARRAY || (Z_TYPE_P(prop_copy) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) {
zval_update_constant(&prop_copy, 0 TSRMLS_CC);
}
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 1a775062cc..d6f232ce41 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -3691,7 +3691,7 @@ void zend_do_end_new_object(znode *result, znode *new_token, znode *argument_lis
}
/* }}} */
-static int zend_constant_ct_subst(znode *result, zval *const_name TSRMLS_DC) /* {{{ */
+static zend_constant* zend_get_ct_const(zval *const_name TSRMLS_DC) /* {{{ */
{
zend_constant *c = NULL;
@@ -3701,14 +3701,27 @@ static int zend_constant_ct_subst(znode *result, zval *const_name TSRMLS_DC) /*
if (zend_u_hash_find(EG(zend_constants), Z_TYPE_P(const_name), lookup_name, lookup_name_len+1, (void **) &c)==SUCCESS) {
if ((c->flags & CONST_CS) && memcmp(c->name.v, Z_UNIVAL_P(const_name).v, UG(unicode)?UBYTES(Z_USTRLEN_P(const_name)):Z_STRLEN_P(const_name))!=0) {
- c = NULL;
+ efree(lookup_name.v);
+ return NULL;
}
} else {
- c = NULL;
+ efree(lookup_name.v);
+ return NULL;
}
efree(lookup_name.v);
}
- if (c && (c->flags & CONST_CT_SUBST)) {
+ if (c->flags & CONST_CT_SUBST) {
+ return c;
+ }
+ return NULL;
+}
+/* }}} */
+
+static int zend_constant_ct_subst(znode *result, zval *const_name TSRMLS_DC) /* {{{ */
+{
+ zend_constant *c = zend_get_ct_const(const_name TSRMLS_CC);
+
+ if (c) {
zval_dtor(const_name);
result->op_type = IS_CONST;
result->u.constant = c->value;
@@ -3720,44 +3733,110 @@ static int zend_constant_ct_subst(znode *result, zval *const_name TSRMLS_DC) /*
}
/* }}} */
-void zend_do_fetch_constant(znode *result, znode *constant_container, znode *constant_name, int mode TSRMLS_DC) /* {{{ */
+void zend_do_fetch_constant(znode *result, znode *constant_container, znode *constant_name, int mode, zend_bool check_namespace TSRMLS_DC) /* {{{ */
{
+ ulong fetch_type = 0;
+ znode tmp;
+
switch (mode) {
case ZEND_CT:
if (constant_container) {
- ulong fetch_type;
-
if (ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_TYPE(constant_container->u.constant), Z_UNIVAL(constant_container->u.constant), Z_UNILEN(constant_container->u.constant))) {
zend_resolve_class_name(constant_container, &fetch_type, 1 TSRMLS_CC);
}
zend_do_fetch_class_name(NULL, constant_container, constant_name TSRMLS_CC);
*result = *constant_container;
- result->u.constant.type = IS_CONSTANT;
+ result->u.constant.type = IS_CONSTANT | fetch_type;
} else if (!zend_constant_ct_subst(result, &constant_name->u.constant TSRMLS_CC)) {
+ if (check_namespace && CG(current_namespace)) {
+ /* We assume we use constant from the current namespace
+ if it is not prefixed. */
+ tmp.op_type = IS_CONST;
+ tmp.u.constant = *CG(current_namespace);
+ zval_copy_ctor(&tmp.u.constant);
+ zend_do_build_namespace_name(&tmp, &tmp, constant_name TSRMLS_CC);
+ *constant_name = tmp;
+ fetch_type = IS_CONSTANT_RT_NS_CHECK;
+ }
*result = *constant_name;
- result->u.constant.type = IS_CONSTANT;
+ result->u.constant.type = IS_CONSTANT | fetch_type;
}
break;
case ZEND_RT:
if (constant_container ||
!zend_constant_ct_subst(result, &constant_name->u.constant TSRMLS_CC)) {
zend_op *opline;
- znode class_node;
if (constant_container) {
- zend_do_fetch_class(&class_node, constant_container TSRMLS_CC);
+ if (constant_container->op_type == IS_CONST &&
+ ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_TYPE(constant_container->u.constant), Z_UNIVAL(constant_container->u.constant), Z_UNILEN(constant_container->u.constant))) {
+ zend_resolve_class_name(constant_container, &fetch_type, 1 TSRMLS_CC);
+ } else {
+ zend_do_fetch_class(&tmp, constant_container TSRMLS_CC);
+ constant_container = &tmp;
+ }
+ } else if (check_namespace && CG(current_namespace)) {
+ /* We assume we use constant from the current namespace
+ if it is not prefixed. */
+ tmp.op_type = IS_CONST;
+ tmp.u.constant = *CG(current_namespace);
+ zval_copy_ctor(&tmp.u.constant);
+ constant_container = &tmp;
+ fetch_type = IS_CONSTANT_RT_NS_CHECK;
}
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_FETCH_CONSTANT;
+ opline->extended_value = fetch_type & ~ZEND_FETCH_CLASS_RT_NS_NAME;
opline->result.op_type = IS_TMP_VAR;
opline->result.u.var = get_temporary_variable(CG(active_op_array));
if (constant_container) {
- opline->op1 = class_node;
+ opline->op1 = *constant_container;
} else {
SET_UNUSED(opline->op1);
}
opline->op2 = *constant_name;
*result = opline->result;
+
+ if (opline->op1.op_type == IS_CONST) {
+ /* Prebuild ns::func name to speedup run-time check.
+ The additional names are stored in additional OP_DATA opcode. */
+ zstr nsname;
+ unsigned int nsname_len;
+
+ opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+ opline->opcode = ZEND_OP_DATA;
+ opline->op1.op_type = IS_CONST;
+ SET_UNUSED(opline->op2);
+
+ nsname = Z_UNIVAL(constant_container->u.constant);
+ nsname_len = Z_UNILEN(constant_container->u.constant);
+ if (fetch_type & ZEND_FETCH_CLASS_RT_NS_NAME) {
+ /* Remove namespace name */
+ if (Z_TYPE(constant_container->u.constant) == IS_UNICODE) {
+ nsname.u = u_memchr(nsname.u, ':', nsname_len) + 2;
+ nsname_len -= (nsname.u - Z_USTRVAL(constant_container->u.constant));
+ } else {
+ nsname.s = memchr(nsname.s, ':', nsname_len) + 2;
+ nsname_len -= (nsname.s - Z_STRVAL(constant_container->u.constant));
+ }
+ }
+
+ Z_TYPE(opline->op1.u.constant) = Z_TYPE(constant_container->u.constant);
+ Z_UNIVAL(opline->op1.u.constant) = zend_u_str_case_fold(Z_TYPE(constant_container->u.constant), nsname, nsname_len, 0, &Z_UNILEN(opline->op1.u.constant));
+ if (UG(unicode)) {
+ Z_USTRVAL(opline->op1.u.constant) = erealloc(Z_USTRVAL(opline->op1.u.constant), UBYTES(Z_USTRLEN(opline->op1.u.constant) + 2 + Z_USTRLEN(constant_name->u.constant) + 1));
+ Z_USTRVAL(opline->op1.u.constant)[Z_USTRLEN(opline->op1.u.constant)] = ':';
+ Z_USTRVAL(opline->op1.u.constant)[Z_USTRLEN(opline->op1.u.constant)+1] = ':';
+ memcpy(Z_USTRVAL(opline->op1.u.constant)+Z_USTRLEN(opline->op1.u.constant)+2, Z_USTRVAL(constant_name->u.constant), UBYTES(Z_USTRLEN(constant_name->u.constant) + 1));
+ } else {
+ Z_STRVAL(opline->op1.u.constant) = erealloc(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant) + 2 + Z_STRLEN(constant_name->u.constant) + 1);
+ Z_STRVAL(opline->op1.u.constant)[Z_STRLEN(opline->op1.u.constant)] = ':';
+ Z_STRVAL(opline->op1.u.constant)[Z_STRLEN(opline->op1.u.constant)+1] = ':';
+ memcpy(Z_STRVAL(opline->op1.u.constant)+Z_STRLEN(opline->op1.u.constant)+2, Z_STRVAL(constant_name->u.constant), Z_STRLEN(constant_name->u.constant) + 1);
+ }
+ Z_UNILEN(opline->op1.u.constant) += 2 + Z_UNILEN(constant_name->u.constant);
+ opline->extended_value = zend_u_hash_func(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant) + 1);
+ }
}
break;
}
@@ -3846,7 +3925,7 @@ void zend_do_add_static_array_element(znode *result, znode *offset, znode *expr)
if (offset) {
zend_uchar utype = Z_TYPE(offset->u.constant);
- switch (Z_TYPE(offset->u.constant)) {
+ switch (Z_TYPE(offset->u.constant) & IS_CONSTANT_TYPE_MASK) {
case IS_CONSTANT:
/* Ugly hack to denote that this value has a constant index */
Z_TYPE_P(element) |= IS_CONSTANT_INDEX;
@@ -5051,6 +5130,37 @@ void zend_do_import(znode *ns_name, znode *new_name TSRMLS_DC) /* {{{ */
}
/* }}} */
+void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC) /* {{{ */
+{
+ zend_op *opline;
+
+ if (zend_get_ct_const(&name->u.constant TSRMLS_CC)) {
+ zend_error(E_COMPILE_ERROR, "Cannot redeclare constant '%R'", Z_TYPE(name->u.constant), Z_UNIVAL(name->u.constant));
+ }
+
+ if (CG(current_namespace)) {
+ /* Prefix constant name with name of current namespace */
+ znode tmp;
+ zstr lcname;
+ uint lcname_len;
+
+ tmp.op_type = IS_CONST;
+ tmp.u.constant = *CG(current_namespace);
+ lcname = zend_u_str_case_fold(Z_TYPE(tmp.u.constant), Z_UNIVAL(tmp.u.constant), Z_UNILEN(tmp.u.constant), 0, &lcname_len);
+ Z_UNIVAL(tmp.u.constant) = lcname;
+ Z_UNILEN(tmp.u.constant) = lcname_len;
+ zend_do_build_namespace_name(&tmp, &tmp, name TSRMLS_CC);
+ *name = tmp;
+ }
+
+ opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+ opline->opcode = ZEND_DECLARE_CONST;
+ SET_UNUSED(opline->result);
+ opline->op1 = *name;
+ opline->op2 = *value;
+}
+/* }}} */
+
void zend_do_end_compilation(TSRMLS_D) /* {{{ */
{
if (CG(current_namespace)) {
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index a87b8eeff2..a8caf053f3 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -470,7 +470,7 @@ void zend_do_pop_object(znode *object TSRMLS_DC);
void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC);
void zend_do_end_new_object(znode *result, znode *new_token, znode *argument_list TSRMLS_DC);
-void zend_do_fetch_constant(znode *result, znode *constant_container, znode *constant_name, int mode TSRMLS_DC);
+void zend_do_fetch_constant(znode *result, znode *constant_container, znode *constant_name, int mode, zend_bool check_namespace TSRMLS_DC);
void zend_do_shell_exec(znode *result, znode *cmd TSRMLS_DC);
@@ -519,6 +519,7 @@ void zend_do_ticks(TSRMLS_D);
void zend_do_abstract_method(znode *function_name, znode *modifiers, znode *body TSRMLS_DC);
+void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC);
void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRMLS_DC);
void zend_do_namespace(znode *name TSRMLS_DC);
void zend_do_import(znode *name, znode *new_name TSRMLS_DC);
diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c
index 3bdd10d3ae..996e77bc19 100644
--- a/Zend/zend_constants.c
+++ b/Zend/zend_constants.c
@@ -258,21 +258,88 @@ ZEND_API void zend_register_string_constant(char *name, uint name_len, char *str
}
/* }}} */
-ZEND_API int zend_u_get_constant(zend_uchar type, zstr name, uint name_len, zval *result, zend_class_entry *scope TSRMLS_DC) /* {{{ */
+ZEND_API int zend_u_get_constant(zend_uchar type, zstr name, uint name_len, zval *result TSRMLS_DC) /* {{{ */
{
zend_constant *c;
int retval = 1;
zstr lookup_name;
+
+ if (zend_u_hash_find(EG(zend_constants), type, name, name_len+1, (void **) &c) == FAILURE) {
+ unsigned int lookup_name_len;
+
+ lookup_name = zend_u_str_case_fold(type, name, name_len, 1, &lookup_name_len);
+
+ if (zend_u_hash_find(EG(zend_constants), type, lookup_name, lookup_name_len+1, (void **) &c)==SUCCESS) {
+ if ((c->flags & CONST_CS) && memcmp(c->name.v, name.v, UG(unicode)?UBYTES(name_len):name_len)!=0) {
+ retval=0;
+ }
+ } else {
+ if (!EG(in_execution)) {
+ retval = 0;
+ } else if (name_len == sizeof(ZEND_HALT_CONSTANT_NAME)-1 && ZEND_U_EQUAL(type, name, name_len, ZEND_HALT_CONSTANT_NAME, sizeof(ZEND_HALT_CONSTANT_NAME)-1)) {
+ char *cfilename;
+ zstr haltname;
+ int len, clen;
+ cfilename = zend_get_executed_filename(TSRMLS_C);
+ clen = strlen(cfilename);
+ /* check for __COMPILER_HALT_OFFSET__ */
+ zend_mangle_property_name(&haltname.s, &len, ZEND_HALT_CONSTANT_NAME,
+ sizeof(ZEND_HALT_CONSTANT_NAME) - 1, cfilename, clen, 0);
+ if (zend_u_hash_find(EG(zend_constants), IS_STRING, haltname, len+1, (void **) &c) == SUCCESS) {
+ retval=1;
+ } else {
+ retval=0;
+ }
+ pefree(haltname.s, 0);
+ } else {
+ retval=0;
+ }
+ }
+ efree(lookup_name.v);
+ }
+
+ if (retval) {
+ *result = c->value;
+ zval_copy_ctor(result);
+ result->refcount = 1;
+ result->is_ref = 0;
+ }
+
+ return retval;
+}
+/* }}} */
+
+ZEND_API int zend_u_get_constant_ex(zend_uchar type, zstr name, uint name_len, zval *result, zend_class_entry *scope, ulong flags TSRMLS_DC) /* {{{ */
+{
+ zend_constant *c;
+ int retval = 1;
zstr colon;
+ /* Skip leading :: */
+ if (type == IS_UNICODE &&
+ name.u[0] == ':' &&
+ name.u[1] == ':') {
+ name.u += 2;
+ name_len -= 2;
+ flags = 0;
+ } else if (type == IS_STRING &&
+ name.s[0] == ':' &&
+ name.s[1] == ':') {
+ name.s += 2;
+ name_len -= 2;
+ flags = 0;
+ }
+
if ((UG(unicode) && (colon.u = u_memrchr(name.u, ':', name_len)) && colon.u > name.u && *(colon.u-1) == ':') ||
(!UG(unicode) && (colon.s = zend_memrchr(name.s, ':', name_len))&& colon.s > name.s && *(colon.s-1) == ':')) {
- /* class constant */
+ /* compound constant name */
zend_class_entry **ce = NULL;
int class_name_len = UG(unicode)?colon.u-name.u-1:colon.s-name.s-1;
int const_name_len = name_len - class_name_len - 2;
zstr constant_name, class_name;
zval **ret_constant;
+ zstr lcname;
+ unsigned int lcname_len;
if (UG(unicode)) {
constant_name.u = colon.u + 1;
@@ -294,16 +361,19 @@ ZEND_API int zend_u_get_constant(zend_uchar type, zstr name, uint name_len, zval
class_name.s = estrndup(name.s, class_name_len);
}
- if (class_name_len == sizeof("self")-1 &&
- ZEND_U_EQUAL(type, class_name, class_name_len, "self", sizeof("self")-1)) {
+ lcname = zend_u_str_case_fold(type, class_name, class_name_len, 0, &lcname_len);
+
+ if (lcname_len == sizeof("self")-1 &&
+ ZEND_U_EQUAL(type, lcname, lcname_len, "self", sizeof("self")-1)) {
if (scope) {
ce = &scope;
} else {
zend_error(E_ERROR, "Cannot access self:: when no class scope is active");
retval = 0;
}
- } else if (class_name_len == sizeof("parent")-1 &&
- ZEND_U_EQUAL(type, class_name, class_name_len, "parent", sizeof("parent")-1)) {
+ efree(lcname.v);
+ } else if (lcname_len == sizeof("parent")-1 &&
+ ZEND_U_EQUAL(type, lcname, lcname_len, "parent", sizeof("parent")-1)) {
if (!scope) {
zend_error(E_ERROR, "Cannot access parent:: when no class scope is active");
} else if (!scope->parent) {
@@ -311,14 +381,57 @@ ZEND_API int zend_u_get_constant(zend_uchar type, zstr name, uint name_len, zval
} else {
ce = &scope->parent;
}
+ efree(lcname.v);
} else {
- if (zend_u_lookup_class(type, class_name, class_name_len, &ce TSRMLS_CC) != SUCCESS) {
+ /* Check for namespace constant */
+ zstr nsname;
+ unsigned int nsname_len;
+
+ /* Concatenate lowercase namespace name and constant name */
+ if (UG(unicode)) {
+ lcname.u = erealloc(lcname.u, UBYTES(lcname_len + 2 + const_name_len + 1));
+ lcname.u[lcname_len] = ':';
+ lcname.u[lcname_len+1] = ':';
+ memcpy(lcname.u+lcname_len+2, constant_name.u, UBYTES(const_name_len + 1));
+ } else {
+ lcname.s = erealloc(lcname.s, lcname_len + 2 + const_name_len + 1);
+ lcname.s[lcname_len] = ':';
+ lcname.s[lcname_len+1] = ':';
+ memcpy(lcname.s+lcname_len+2, constant_name.s, const_name_len + 1);
+ }
+ lcname_len += 2 + const_name_len;
+
+ nsname = lcname;
+ nsname_len = lcname_len;
+ if (flags & ZEND_FETCH_CLASS_RT_NS_NAME) {
+ /* Remove namespace name */
+ if (UG(unicode)) {
+ nsname.u = u_memchr(nsname.u, ':', nsname_len) + 2;
+ nsname_len -= (nsname.u - lcname.u);
+ } else {
+ nsname.s = memchr(nsname.s, ':', nsname_len) + 2;
+ nsname_len -= (nsname.s - lcname.s);
+ }
+ }
+
+ if (zend_u_hash_find(EG(zend_constants), type, nsname, nsname_len+1, (void **) &c) == SUCCESS) {
+ efree(lcname.v);
+ efree(class_name.v);
+ *result = c->value;
+ zval_update_constant_ex(&result, (void*)1, NULL TSRMLS_CC);
+ zval_copy_ctor(result);
+ result->refcount = 1;
+ result->is_ref = 0;
+ return 1;
+ }
+ efree(lcname.v);
+
+ /* Check for class */
+ if (zend_u_lookup_class(type, class_name, class_name_len, &ce TSRMLS_CC) != SUCCESS &&
+ (flags & ZEND_FETCH_CLASS_RT_NS_CHECK) != 0) {
retval = 0;
if ((UG(unicode) && (colon.u = u_memrchr(class_name.u, ':', class_name_len)) && colon.u > class_name.u && *(colon.u-1) == ':') ||
(!UG(unicode) && (colon.s = zend_memrchr(class_name.s, ':', class_name_len))&& colon.s > class_name.s && *(colon.s-1) == ':')) {
- zend_class_entry **pce;
- zstr lcname;
- unsigned int lcname_len;
if (UG(unicode)) {
colon.u++;
@@ -342,7 +455,16 @@ ZEND_API int zend_u_get_constant(zend_uchar type, zstr name, uint name_len, zval
retval = 0;
}
} else {
- zend_error(E_ERROR, "Class '%R' not found", type, class_name);
+ if ((flags & ZEND_FETCH_CLASS_RT_NS_NAME) == 0) {
+ if ((flags & IS_CONSTANT_RT_NS_CHECK) != 0) {
+ name = constant_name;
+ name_len = const_name_len;
+ efree(class_name.v);
+ retval = 1;
+ return zend_u_get_constant(type, name, name_len, result TSRMLS_CC);
+ }
+ zend_error(E_ERROR, "Class '%R' not found", type, class_name);
+ }
retval = 0;
}
efree(class_name.v);
@@ -356,54 +478,13 @@ ZEND_API int zend_u_get_constant(zend_uchar type, zstr name, uint name_len, zval
return retval;
}
- if (zend_u_hash_find(EG(zend_constants), type, name, name_len+1, (void **) &c) == FAILURE) {
- unsigned int lookup_name_len;
-
- lookup_name = zend_u_str_case_fold(type, name, name_len, 1, &lookup_name_len);
-
- if (zend_u_hash_find(EG(zend_constants), type, lookup_name, lookup_name_len+1, (void **) &c)==SUCCESS) {
- if ((c->flags & CONST_CS) && memcmp(c->name.v, name.v, UG(unicode)?UBYTES(name_len):name_len)!=0) {
- retval=0;
- }
- } else {
- if (!EG(in_execution)) {
- retval = 0;
- } else if (name_len == sizeof(ZEND_HALT_CONSTANT_NAME)-1 && ZEND_U_EQUAL(type, name, name_len, ZEND_HALT_CONSTANT_NAME, sizeof(ZEND_HALT_CONSTANT_NAME)-1)) {
- char *cfilename;
- zstr haltname;
- int len, clen;
- cfilename = zend_get_executed_filename(TSRMLS_C);
- clen = strlen(cfilename);
- /* check for __COMPILER_HALT_OFFSET__ */
- zend_mangle_property_name(&haltname.s, &len, ZEND_HALT_CONSTANT_NAME,
- sizeof(ZEND_HALT_CONSTANT_NAME) - 1, cfilename, clen, 0);
- if (zend_u_hash_find(EG(zend_constants), IS_STRING, haltname, len+1, (void **) &c) == SUCCESS) {
- retval=1;
- } else {
- retval=0;
- }
- pefree(haltname.s, 0);
- } else {
- retval=0;
- }
- }
- efree(lookup_name.v);
- }
-
- if (retval) {
- *result = c->value;
- zval_copy_ctor(result);
- result->refcount = 1;
- result->is_ref = 0;
- }
-
- return retval;
+ return zend_u_get_constant(type, name, name_len, result TSRMLS_CC);
}
/* }}} */
ZEND_API int zend_get_constant(char *name, uint name_len, zval *result TSRMLS_DC) /* {{{ */
{
- return zend_u_get_constant(IS_STRING, ZSTR(name), name_len, result, NULL TSRMLS_CC);
+ return zend_u_get_constant_ex(IS_STRING, ZSTR(name), name_len, result, NULL, 0 TSRMLS_CC);
}
/* }}} */
@@ -461,7 +542,7 @@ ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC) /* {{{ */
free(c->name.s);
c->name.u = ustr;
}
- if (Z_TYPE(c->value) == IS_STRING || Z_TYPE(c->value) == IS_CONSTANT) {
+ if (Z_TYPE(c->value) == IS_STRING || (Z_TYPE(c->value) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) {
ustr = pemalloc(UBYTES(Z_STRLEN(c->value)+1), c->flags & CONST_PERSISTENT);
u_charsToUChars(Z_STRVAL(c->value), ustr, Z_STRLEN(c->value)+1);
pefree(Z_STRVAL(c->value), c->flags & CONST_PERSISTENT);
diff --git a/Zend/zend_constants.h b/Zend/zend_constants.h
index d4fabfc228..898b9a0726 100644
--- a/Zend/zend_constants.h
+++ b/Zend/zend_constants.h
@@ -56,7 +56,8 @@ int zend_shutdown_constants(TSRMLS_D);
void zend_register_standard_constants(TSRMLS_D);
void clean_non_persistent_constants(TSRMLS_D);
ZEND_API int zend_get_constant(char *name, uint name_len, zval *result TSRMLS_DC);
-ZEND_API int zend_u_get_constant(zend_uchar type, zstr name, uint name_len, zval *result, zend_class_entry *scope TSRMLS_DC);
+ZEND_API int zend_u_get_constant(zend_uchar type, zstr name, uint name_len, zval *result TSRMLS_DC);
+ZEND_API int zend_u_get_constant_ex(zend_uchar type, zstr name, uint name_len, zval *result, zend_class_entry *scope, ulong flags TSRMLS_DC);
ZEND_API void zend_register_long_constant(char *name, uint name_len, long lval, int flags, int module_number TSRMLS_DC);
ZEND_API void zend_register_double_constant(char *name, uint name_len, double dval, int flags, int module_number TSRMLS_DC);
ZEND_API void zend_register_string_constant(char *name, uint name_len, char *strval, int flags, int module_number TSRMLS_DC);
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 8dfd69af2b..5c2661fd0e 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -485,10 +485,11 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *sco
zend_bool inline_change = (zend_bool) (zend_uintptr_t) arg;
zval const_value;
zstr colon;
+ int len;
if (IS_CONSTANT_VISITED(p)) {
zend_error(E_ERROR, "Cannot declare self-referencing constant '%v'", Z_UNIVAL_P(p));
- } else if (Z_TYPE_P(p) == IS_CONSTANT) {
+ } else if ((Z_TYPE_P(p) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) {
int refcount;
zend_uchar is_ref;
@@ -500,10 +501,15 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *sco
refcount = p->refcount;
is_ref = p->is_ref;
- if (!zend_u_get_constant(ZEND_STR_TYPE, Z_UNIVAL_P(p), Z_UNILEN_P(p), &const_value, scope TSRMLS_CC)) {
- if ((UG(unicode) && (colon.u = u_memchr(Z_USTRVAL_P(p), ':', Z_USTRLEN_P(p))) && colon.u[1] == ':') ||
- (!UG(unicode) && (colon.s = memchr(Z_STRVAL_P(p), ':', Z_STRLEN_P(p))) && colon.s[1] == ':')) {
- zend_error(E_ERROR, "Undefined class constant '%v'", Z_UNIVAL_P(p));
+ if (!zend_u_get_constant_ex(ZEND_STR_TYPE, Z_UNIVAL_P(p), Z_UNILEN_P(p), &const_value, scope, Z_TYPE_P(p) TSRMLS_CC)) {
+ if ((UG(unicode) && (colon.u = u_memrchr(Z_USTRVAL_P(p), ':', Z_USTRLEN_P(p))) && colon.u > Z_USTRVAL_P(p) && *(colon.u-1) == ':') ||
+ (!UG(unicode) && (colon.s = zend_memrchr(Z_STRVAL_P(p), ':', Z_STRLEN_P(p))) && colon.s > Z_STRVAL_P(p) && *(colon.s-1) == ':')) {
+ if (UG(unicode)) {
+ colon.u++;
+ } else {
+ colon.s++;
+ }
+ zend_error(E_ERROR, "Undefined class constant '%v'", colon);
}
zend_error(E_NOTICE, "Use of undefined constant %v - assumed '%v'",
Z_UNIVAL_P(p),
@@ -543,7 +549,7 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *sco
zend_hash_move_forward(Z_ARRVAL_P(p));
continue;
}
- if (!zend_u_get_constant(ZEND_STR_TYPE, str_index, str_index_len-1, &const_value, scope TSRMLS_CC)) {
+ if (!zend_u_get_constant_ex(ZEND_STR_TYPE, str_index, str_index_len-1, &const_value, scope, 0 TSRMLS_CC)) {
if ((UG(unicode) && (colon.u = u_memchr(str_index.u, ':', str_index_len-1)) && colon.u[1] == ':') ||
(!UG(unicode) && (colon.s = memchr(str_index.s, ':', str_index_len-1)) && colon.s[1] == ':')) {
zend_error(E_ERROR, "Undefined class constant '%v'", str_index);
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index 4c1e6f470a..9b11308b1a 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -174,8 +174,13 @@ top_statement:
| T_NAMESPACE namespace_name ';' { zend_do_namespace(&$2 TSRMLS_CC); }
| T_IMPORT namespace_name ';' { zend_do_import(&$2, NULL TSRMLS_CC); }
| T_IMPORT namespace_name T_AS T_STRING ';' { zend_do_import(&$2, &$4 TSRMLS_CC); }
+ | constant_declaration ';'
;
+constant_declaration:
+ constant_declaration ',' T_STRING '=' static_scalar { zend_do_declare_constant(&$3, &$5 TSRMLS_CC); }
+ | T_CONST T_STRING '=' static_scalar { zend_do_declare_constant(&$2, &$4 TSRMLS_CC); }
+;
inner_statement_list:
inner_statement_list { zend_do_extended_info(TSRMLS_C); } inner_statement { HANDLE_INTERACTIVE(); }
@@ -722,7 +727,8 @@ common_scalar:
static_scalar: /* compile-time evaluated scalars */
common_scalar { $$ = $1; }
- | T_STRING { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT TSRMLS_CC); }
+ | T_STRING { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT, 1 TSRMLS_CC); }
+ | T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, NULL, &$2, ZEND_CT, 0 TSRMLS_CC); }
| '+' static_scalar { $$ = $2; }
| '-' static_scalar { zval minus_one; Z_TYPE(minus_one) = IS_LONG; Z_LVAL(minus_one) = -1; mul_function(&$2.u.constant, &$2.u.constant, &minus_one TSRMLS_CC); $$ = $2; }
| T_ARRAY '(' static_array_pair_list ')' { $$ = $3; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; }
@@ -730,11 +736,12 @@ static_scalar: /* compile-time evaluated scalars */
;
static_class_constant:
- fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_CT TSRMLS_CC); }
+ fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_CT, 0 TSRMLS_CC); }
;
scalar:
- T_STRING { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT TSRMLS_CC); }
+ T_STRING { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT, 1 TSRMLS_CC); }
+ | T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, NULL, &$2, ZEND_RT, 0 TSRMLS_CC); }
| T_STRING_VARNAME { $$ = $1; }
| class_constant { $$ = $1; }
| common_scalar { $$ = $1; }
@@ -945,8 +952,8 @@ isset_variables:
;
class_constant:
- fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT TSRMLS_CC); }
- | variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT TSRMLS_CC); }
+ fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT, 0 TSRMLS_CC); }
+ | variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT, 0 TSRMLS_CC); }
;
%%
diff --git a/Zend/zend_variables.c b/Zend/zend_variables.c
index a88d58dd12..cafcdb4b12 100644
--- a/Zend/zend_variables.c
+++ b/Zend/zend_variables.c
@@ -28,7 +28,7 @@
ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC) /* {{{ */
{
- switch (Z_TYPE_P(zvalue) & ~IS_CONSTANT_INDEX) {
+ switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) {
case IS_CONSTANT: {
TSRMLS_FETCH();
@@ -81,7 +81,7 @@ dtor_unicode:
ZEND_API void _zval_internal_dtor(zval *zvalue ZEND_FILE_LINE_DC) /* {{{ */
{
- switch (Z_TYPE_P(zvalue) & ~IS_CONSTANT_INDEX) {
+ switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) {
case IS_CONSTANT: {
TSRMLS_FETCH();
@@ -120,7 +120,7 @@ ZEND_API void zval_add_ref(zval **p) /* {{{ */
ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC) /* {{{ */
{
- switch (Z_TYPE_P(zvalue)) {
+ switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) {
case IS_RESOURCE: {
TSRMLS_FETCH();
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index f933a00cb5..7462e8def7 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2466,7 +2466,7 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST)
zend_free_op free_res;
if (zend_ptr_stack_get_arg(arg_num, (void **) &param TSRMLS_CC)==FAILURE) {
- if (Z_TYPE(opline->op2.u.constant) == IS_CONSTANT || Z_TYPE(opline->op2.u.constant)==IS_CONSTANT_ARRAY) {
+ if ((Z_TYPE(opline->op2.u.constant) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || Z_TYPE(opline->op2.u.constant)==IS_CONSTANT_ARRAY) {
zval *default_value;
ALLOC_ZVAL(default_value);
@@ -2700,37 +2700,51 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMP|VAR|UNUSED|CV, ANY)
ZEND_VM_NEXT_OPCODE();
}
-ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|UNUSED, CONST)
+ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|UNUSED|CONST, CONST)
{
zend_op *opline = EX(opline);
zend_class_entry *ce = NULL;
zval **value;
if (OP1_TYPE == IS_UNUSED) {
-/* This seems to be a reminant of namespaces
- if (EG(scope)) {
- ce = EG(scope);
- if (zend_hash_find(&ce->constants_table, Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) {
- zval_update_constant(value, (void *) 1 TSRMLS_CC);
- EX_T(opline->result.u.var).tmp_var = **value;
- zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
- ZEND_VM_NEXT_OPCODE();
- }
- }
-*/
- if (!zend_u_get_constant(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var, NULL TSRMLS_CC)) {
+ if (!zend_u_get_constant(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) {
zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'",
- Z_TYPE(opline->op2.u.constant),
- Z_UNIVAL(opline->op2.u.constant),
- Z_TYPE(opline->op2.u.constant),
- Z_UNIVAL(opline->op2.u.constant));
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant),
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant));
EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;
zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
}
ZEND_VM_NEXT_OPCODE();
- }
+ } else if (OP1_TYPE == IS_CONST) {
+ zend_op *op_data = opline + 1;
+ zend_constant *c;
+
+ ZEND_VM_INC_OPCODE();
- ce = EX_T(opline->op1.u.var).class_entry;
+ /* try a constant in namespace */
+ if (zend_u_hash_quick_find(EG(zend_constants), Z_TYPE(op_data->op1.u.constant), Z_UNIVAL(op_data->op1.u.constant), Z_UNILEN(op_data->op1.u.constant)+1, op_data->extended_value, (void **) &c)==SUCCESS) {
+ EX_T(opline->result.u.var).tmp_var = c->value;
+ zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
+ ZEND_VM_NEXT_OPCODE();
+ } else if ((opline->extended_value & IS_CONSTANT_RT_NS_CHECK) != 0) {
+ if (!zend_u_get_constant(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) {
+ zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'",
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant),
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant));
+ EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;
+ zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
+ }
+ ZEND_VM_NEXT_OPCODE();
+ }
+
+ /* no constant found. try a constant in class */
+ ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC);
+ if (!ce) {
+ zend_error_noreturn(E_ERROR, "Undefined class constant '%R'", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant));
+ }
+ } else {
+ ce = EX_T(opline->op1.u.var).class_entry;
+ }
if (zend_u_hash_find(&ce->constants_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) {
zend_class_entry *old_scope = EG(scope);
@@ -4116,4 +4130,43 @@ ZEND_VM_HANDLER(151, ZEND_U_NORMALIZE, CONST|TMP|VAR|CV, ANY)
ZEND_VM_NEXT_OPCODE();
}
+ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST)
+{
+ zend_op *opline = EX(opline);
+ zend_free_op free_op1, free_op2;
+ zval *name = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ zval *val = GET_OP2_ZVAL_PTR(BP_VAR_R);
+ zend_constant c;
+
+ if ((Z_TYPE_P(val) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || Z_TYPE_P(val) == IS_CONSTANT_ARRAY) {
+ zval tmp = *val;
+ zval *tmp_ptr = &tmp;
+
+ if (Z_TYPE_P(val) == IS_CONSTANT_ARRAY) {
+ zval_copy_ctor(&tmp);
+ }
+ INIT_PZVAL(&tmp);
+ zval_update_constant(&tmp_ptr, NULL TSRMLS_CC);
+ c.value = *tmp_ptr;
+ } else {
+ c.value = *val;
+ zval_copy_ctor(&c.value);
+ }
+ c.flags = CONST_CS; /* non persistent, case sensetive */
+ if (Z_TYPE_P(name) == IS_UNICODE) {
+ c.name.u = zend_ustrndup(Z_USTRVAL_P(name), Z_USTRLEN_P(name));
+ } else {
+ c.name.s = zend_strndup(Z_STRVAL_P(name), Z_STRLEN_P(name));
+ }
+ c.name_len = Z_UNILEN_P(name)+1;
+ c.module_number = PHP_USER_CONSTANT;
+
+ if (zend_u_register_constant(Z_TYPE_P(name), &c TSRMLS_CC) == FAILURE) {
+ }
+
+ FREE_OP1();
+ FREE_OP2();
+ ZEND_VM_NEXT_OPCODE();
+}
+
ZEND_VM_EXPORT_HELPER(zend_do_fcall, zend_do_fcall_common_helper)
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 590660c945..1fa7ac8cfc 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -757,7 +757,7 @@ static int ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zend_free_op free_res;
if (zend_ptr_stack_get_arg(arg_num, (void **) &param TSRMLS_CC)==FAILURE) {
- if (Z_TYPE(opline->op2.u.constant) == IS_CONSTANT || Z_TYPE(opline->op2.u.constant)==IS_CONSTANT_ARRAY) {
+ if ((Z_TYPE(opline->op2.u.constant) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || Z_TYPE(opline->op2.u.constant)==IS_CONSTANT_ARRAY) {
zval *default_value;
ALLOC_ZVAL(default_value);
@@ -2651,6 +2651,67 @@ static int ZEND_CASE_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
ZEND_VM_NEXT_OPCODE();
}
+static int ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ zend_op *opline = EX(opline);
+ zend_class_entry *ce = NULL;
+ zval **value;
+
+ if (IS_CONST == IS_UNUSED) {
+ if (!zend_u_get_constant(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) {
+ zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'",
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant),
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant));
+ EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;
+ zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
+ }
+ ZEND_VM_NEXT_OPCODE();
+ } else if (IS_CONST == IS_CONST) {
+ zend_op *op_data = opline + 1;
+ zend_constant *c;
+
+ ZEND_VM_INC_OPCODE();
+
+ /* try a constant in namespace */
+ if (zend_u_hash_quick_find(EG(zend_constants), Z_TYPE(op_data->op1.u.constant), Z_UNIVAL(op_data->op1.u.constant), Z_UNILEN(op_data->op1.u.constant)+1, op_data->extended_value, (void **) &c)==SUCCESS) {
+ EX_T(opline->result.u.var).tmp_var = c->value;
+ zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
+ ZEND_VM_NEXT_OPCODE();
+ } else if ((opline->extended_value & IS_CONSTANT_RT_NS_CHECK) != 0) {
+ if (!zend_u_get_constant(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) {
+ zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'",
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant),
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant));
+ EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;
+ zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
+ }
+ ZEND_VM_NEXT_OPCODE();
+ }
+
+ /* no constant found. try a constant in class */
+ ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC);
+ if (!ce) {
+ zend_error_noreturn(E_ERROR, "Undefined class constant '%R'", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant));
+ }
+ } else {
+ ce = EX_T(opline->op1.u.var).class_entry;
+ }
+
+ if (zend_u_hash_find(&ce->constants_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) {
+ zend_class_entry *old_scope = EG(scope);
+
+ EG(scope) = ce;
+ zval_update_constant(value, (void *) 1 TSRMLS_CC);
+ EG(scope) = old_scope;
+ EX_T(opline->result.u.var).tmp_var = **value;
+ zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
+ } else {
+ zend_error_noreturn(E_ERROR, "Undefined class constant '%R'", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant));
+ }
+
+ ZEND_VM_NEXT_OPCODE();
+}
+
static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_op *opline = EX(opline);
@@ -2745,6 +2806,44 @@ static int ZEND_INIT_ARRAY_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
}
}
+static int ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+ zend_op *opline = EX(opline);
+
+ zval *name = &opline->op1.u.constant;
+ zval *val = &opline->op2.u.constant;
+ zend_constant c;
+
+ if ((Z_TYPE_P(val) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || Z_TYPE_P(val) == IS_CONSTANT_ARRAY) {
+ zval tmp = *val;
+ zval *tmp_ptr = &tmp;
+
+ if (Z_TYPE_P(val) == IS_CONSTANT_ARRAY) {
+ zval_copy_ctor(&tmp);
+ }
+ INIT_PZVAL(&tmp);
+ zval_update_constant(&tmp_ptr, NULL TSRMLS_CC);
+ c.value = *tmp_ptr;
+ } else {
+ c.value = *val;
+ zval_copy_ctor(&c.value);
+ }
+ c.flags = CONST_CS; /* non persistent, case sensetive */
+ if (Z_TYPE_P(name) == IS_UNICODE) {
+ c.name.u = zend_ustrndup(Z_USTRVAL_P(name), Z_USTRLEN_P(name));
+ } else {
+ c.name.s = zend_strndup(Z_STRVAL_P(name), Z_STRLEN_P(name));
+ }
+ c.name_len = Z_UNILEN_P(name)+1;
+ c.module_number = PHP_USER_CONSTANT;
+
+ if (zend_u_register_constant(Z_TYPE_P(name), &c TSRMLS_CC) == FAILURE) {
+ }
+
+
+ ZEND_VM_NEXT_OPCODE();
+}
+
static int ZEND_ADD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
zend_op *opline = EX(opline);
@@ -10016,30 +10115,44 @@ static int ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
zval **value;
if (IS_VAR == IS_UNUSED) {
-/* This seems to be a reminant of namespaces
- if (EG(scope)) {
- ce = EG(scope);
- if (zend_hash_find(&ce->constants_table, Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) {
- zval_update_constant(value, (void *) 1 TSRMLS_CC);
- EX_T(opline->result.u.var).tmp_var = **value;
- zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
- ZEND_VM_NEXT_OPCODE();
- }
- }
-*/
- if (!zend_u_get_constant(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var, NULL TSRMLS_CC)) {
+ if (!zend_u_get_constant(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) {
zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'",
- Z_TYPE(opline->op2.u.constant),
- Z_UNIVAL(opline->op2.u.constant),
- Z_TYPE(opline->op2.u.constant),
- Z_UNIVAL(opline->op2.u.constant));
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant),
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant));
EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;
zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
}
ZEND_VM_NEXT_OPCODE();
- }
+ } else if (IS_VAR == IS_CONST) {
+ zend_op *op_data = opline + 1;
+ zend_constant *c;
+
+ ZEND_VM_INC_OPCODE();
- ce = EX_T(opline->op1.u.var).class_entry;
+ /* try a constant in namespace */
+ if (zend_u_hash_quick_find(EG(zend_constants), Z_TYPE(op_data->op1.u.constant), Z_UNIVAL(op_data->op1.u.constant), Z_UNILEN(op_data->op1.u.constant)+1, op_data->extended_value, (void **) &c)==SUCCESS) {
+ EX_T(opline->result.u.var).tmp_var = c->value;
+ zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
+ ZEND_VM_NEXT_OPCODE();
+ } else if ((opline->extended_value & IS_CONSTANT_RT_NS_CHECK) != 0) {
+ if (!zend_u_get_constant(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) {
+ zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'",
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant),
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant));
+ EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;
+ zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
+ }
+ ZEND_VM_NEXT_OPCODE();
+ }
+
+ /* no constant found. try a constant in class */
+ ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC);
+ if (!ce) {
+ zend_error_noreturn(E_ERROR, "Undefined class constant '%R'", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant));
+ }
+ } else {
+ ce = EX_T(opline->op1.u.var).class_entry;
+ }
if (zend_u_hash_find(&ce->constants_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) {
zend_class_entry *old_scope = EG(scope);
@@ -16724,30 +16837,44 @@ static int ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG
zval **value;
if (IS_UNUSED == IS_UNUSED) {
-/* This seems to be a reminant of namespaces
- if (EG(scope)) {
- ce = EG(scope);
- if (zend_hash_find(&ce->constants_table, Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) {
- zval_update_constant(value, (void *) 1 TSRMLS_CC);
- EX_T(opline->result.u.var).tmp_var = **value;
- zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
- ZEND_VM_NEXT_OPCODE();
- }
- }
-*/
- if (!zend_u_get_constant(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var, NULL TSRMLS_CC)) {
+ if (!zend_u_get_constant(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) {
zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'",
- Z_TYPE(opline->op2.u.constant),
- Z_UNIVAL(opline->op2.u.constant),
- Z_TYPE(opline->op2.u.constant),
- Z_UNIVAL(opline->op2.u.constant));
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant),
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant));
EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;
zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
}
ZEND_VM_NEXT_OPCODE();
- }
+ } else if (IS_UNUSED == IS_CONST) {
+ zend_op *op_data = opline + 1;
+ zend_constant *c;
+
+ ZEND_VM_INC_OPCODE();
+
+ /* try a constant in namespace */
+ if (zend_u_hash_quick_find(EG(zend_constants), Z_TYPE(op_data->op1.u.constant), Z_UNIVAL(op_data->op1.u.constant), Z_UNILEN(op_data->op1.u.constant)+1, op_data->extended_value, (void **) &c)==SUCCESS) {
+ EX_T(opline->result.u.var).tmp_var = c->value;
+ zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
+ ZEND_VM_NEXT_OPCODE();
+ } else if ((opline->extended_value & IS_CONSTANT_RT_NS_CHECK) != 0) {
+ if (!zend_u_get_constant(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) {
+ zend_error(E_NOTICE, "Use of undefined constant %R - assumed '%R'",
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant),
+ Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant));
+ EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;
+ zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
+ }
+ ZEND_VM_NEXT_OPCODE();
+ }
- ce = EX_T(opline->op1.u.var).class_entry;
+ /* no constant found. try a constant in class */
+ ce = zend_u_fetch_class(Z_TYPE(opline->op1.u.constant), Z_UNIVAL(opline->op1.u.constant), Z_UNILEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC);
+ if (!ce) {
+ zend_error_noreturn(E_ERROR, "Undefined class constant '%R'", Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant));
+ }
+ } else {
+ ce = EX_T(opline->op1.u.var).class_entry;
+ }
if (zend_u_hash_find(&ce->constants_table, Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) {
zend_class_entry *old_scope = EG(scope);
@@ -30882,7 +31009,7 @@ void zend_init_opcodes_handlers(void)
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
- ZEND_NULL_HANDLER,
+ ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
@@ -31982,7 +32109,7 @@ void zend_init_opcodes_handlers(void)
ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER,
ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER,
ZEND_RAISE_ABSTRACT_ERROR_SPEC_HANDLER,
- ZEND_NULL_HANDLER,
+ ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h
index 2a56b4b8d3..b1d88da213 100644
--- a/Zend/zend_vm_opcodes.h
+++ b/Zend/zend_vm_opcodes.h
@@ -142,6 +142,7 @@
#define ZEND_DECLARE_INHERITED_CLASS 140
#define ZEND_DECLARE_FUNCTION 141
#define ZEND_RAISE_ABSTRACT_ERROR 142
+#define ZEND_DECLARE_CONST 143
#define ZEND_ADD_INTERFACE 144
#define ZEND_VERIFY_ABSTRACT_CLASS 146
#define ZEND_ASSIGN_DIM 147
diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c
index 8eb725affb..486278cfc3 100644
--- a/ext/standard/basic_functions.c
+++ b/ext/standard/basic_functions.c
@@ -4188,7 +4188,7 @@ PHP_FUNCTION(constant)
return;
}
- if (!zend_u_get_constant(const_type, const_name, const_name_len, return_value, NULL TSRMLS_CC)) {
+ if (!zend_u_get_constant_ex(const_type, const_name, const_name_len, return_value, NULL, 0 TSRMLS_CC)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't find constant %R", const_type, const_name);
RETURN_NULL();
}