Namespace resolution streamlining patch

[DOC] new resolution rules should be documented soon
This commit is contained in:
Stanislav Malyshev 2008-11-11 19:45:29 +00:00
parent caa133b3d3
commit 1b4134c07b
30 changed files with 440 additions and 686 deletions

View File

@ -20,26 +20,21 @@ function test3(\foo\bar $bar) {
function test4(\Exception $e) {
echo "ok\n";
}
function test5(Exception $e) {
echo "ok\n";
}
function test6(\bar $bar) {
function test5(\bar $bar) {
echo "bug\n";
}
$x = new bar();
$y = new Exception();
$y = new \Exception();
test1($x);
test2($x);
test3($x);
test4($y);
test5($y);
test6($x);
test5($x);
--EXPECTF--
ok
ok
ok
ok
ok
Catchable fatal error: Argument 1 passed to foo\test6() must be an instance of bar, instance of foo\bar given, called in %sbug42802.php on line 23
Catchable fatal error: Argument 1 passed to foo\test5() must be an instance of bar, instance of foo\bar given, called in %sbug42802.php on line %d and defined in %sbug42802.php on line %d

View File

@ -15,6 +15,7 @@ const C = "foo\\foo\\foo::C\n";
}
namespace foo;
use \ArrayObject;
const C = "foo\\C\n";
const I = 11;
@ -89,7 +90,6 @@ echo foo::C;
echo \foo\foo::C;
echo ArrayObject::STD_PROP_LIST . "\n";
echo E_ERROR . "\n";
echo "second\n";
echo \foo\foo::C1;
echo \foo\foo::C2;

View File

@ -10,6 +10,6 @@ class foo {
$foo = new foo;
$foo->bar($foo); // Ok!
$foo->bar(new stdclass); // Error, ok!
$foo->bar(new \stdclass); // Error, ok!
--EXPECTF--
Catchable fatal error: Argument 1 passed to foobar\foo::bar() must be an instance of foobar\foo, instance of stdClass given, called in %sbug43332_1.php on line 10 and defined in %sbug43332_1.php on line 5

View File

@ -11,7 +11,7 @@ class_alias('foo\bar', 'baz');
use \baz as stdClass;
var_dump(new foo\bar);
var_dump(new bar);
var_dump(new stdClass);
var_dump(new \baz);

View File

@ -15,7 +15,7 @@ use test\ns1 as ns2;
use test\ns1;
Foo::bar();
test\ns1\Foo::bar();
\test\ns1\Foo::bar();
Bar::bar();
ns2\Foo::bar();
ns1\Foo::bar();

View File

@ -1,9 +1,9 @@
--TEST--
004: Name conflict (php name)
004: Using global class name from namespace (unqualified - fail)
--FILE--
<?php
namespace test\ns1;
echo get_class(new Exception()),"\n";
--EXPECT--
Exception
--EXPECTF--
Fatal error: Class 'test\ns1\Exception' not found in %sns_004.php on line %d

View File

@ -15,35 +15,27 @@ class Foo {
}
}
new Foo();
new X\Foo();
new Y\Foo();
new \X\Foo();
Foo::bar();
X\Foo::bar();
Y\Foo::bar();
\X\Foo::bar();
echo Foo::C;
echo X\Foo::C;
echo Y\Foo::C;
echo \X\Foo::C;
echo Foo::$var;
echo X\Foo::$var;
echo Y\Foo::$var;
echo \X\Foo::$var;
--EXPECT--
class ok
class ok
class ok
class ok
method ok
method ok
method ok
method ok
const ok
const ok
const ok
const ok
var ok
var ok
var ok
var ok

View File

@ -10,23 +10,18 @@ class Foo {
function f1($x=Foo::C) {
echo $x;
}
function f2($x=A\Foo::C) {
function f2($x=B\Foo::C) {
echo $x;
}
function f3($x=B\Foo::C) {
echo $x;
}
function f4($x=\A\Foo::C) {
function f3($x=\A\Foo::C) {
echo $x;
}
echo Foo::C;
echo A\Foo::C;
echo B\Foo::C;
echo \A\Foo::C;
f1();
f2();
f3();
f4();
--EXPECT--
ok
ok
@ -34,5 +29,3 @@ ok
ok
ok
ok
ok
ok

View File

@ -5,6 +5,8 @@
--FILE--
<?php
namespace A;
use \ArrayObject;
function f1($x = ArrayObject::STD_PROP_LIST) {
var_dump($x);
}

View File

@ -15,25 +15,20 @@ function f1($x = ArrayObject::STD_PROP_LIST) {
function f2($x = \ArrayObject::STD_PROP_LIST) {
var_dump($x);
}
function f3($x = A\ArrayObject::STD_PROP_LIST) {
function f3($x = \A\ArrayObject::STD_PROP_LIST) {
var_dump($x);
}
function f4($x = B\ArrayObject::STD_PROP_LIST) {
var_dump($x);
}
function f5($x = \A\ArrayObject::STD_PROP_LIST) {
var_dump($x);
}
var_dump(ArrayObject::STD_PROP_LIST);
var_dump(\ArrayObject::STD_PROP_LIST);
var_dump(A\ArrayObject::STD_PROP_LIST);
var_dump(B\ArrayObject::STD_PROP_LIST);
var_dump(\A\ArrayObject::STD_PROP_LIST);
f1();
f2();
f3();
f4();
f5();
?>
--EXPECT--
int(2)
@ -41,8 +36,6 @@ int(1)
int(2)
int(2)
int(2)
int(2)
int(1)
int(2)
int(2)
int(2)

View File

@ -15,35 +15,27 @@ class X {
}
}
new X();
new X\X();
new Y\X();
new \X\X();
X::bar();
X\X::bar();
Y\X::bar();
\X\X::bar();
echo X::C;
echo X\X::C;
echo Y\X::C;
echo \X\X::C;
echo X::$var;
echo X\X::$var;
echo Y\X::$var;
echo \X\X::$var;
--EXPECT--
class ok
class ok
class ok
class ok
method ok
method ok
method ok
method ok
const ok
const ok
const ok
const ok
var ok
var ok
var ok
var ok

View File

@ -7,7 +7,7 @@ function foo() {
echo "ok\n";
}
\Exception\foo();
Exception::bar();
\Exception::bar();
--EXPECTF--
ok

View File

@ -6,13 +6,13 @@
<?php
namespace test\ns1;
class Foo implements SplObserver {
class Foo implements \SplObserver {
function update(\SplSubject $x) {
echo "ok\n";
}
}
class Bar implements SplSubject {
class Bar implements \SplSubject {
function attach(\SplObserver $x) {
echo "ok\n";
}

View File

@ -11,23 +11,18 @@ class Foo {
function test2(\test\ns1\Foo $x) {
echo "ok\n";
}
function test3(Exception $x) {
echo "ok\n";
}
function test4(\Exception $x) {
function test3(\Exception $x) {
echo "ok\n";
}
}
$foo = new Foo();
$ex = new Exception();
$ex = new \Exception();
$foo->test1($foo);
$foo->test2($foo);
$foo->test3($ex);
$foo->test4($ex);
?>
--EXPECT--
ok
ok
ok
ok

View File

@ -5,14 +5,15 @@
--FILE--
<?php
namespace test\ns1;
use \SplObserver;
class Foo implements SplObserver {
function update(SplSubject $x) {
function update(\SplSubject $x) {
echo "ok\n";
}
}
class Bar implements SplSubject {
class Bar implements \SplSubject {
function attach(SplObserver $x) {
echo "ok\n";
}

View File

@ -42,6 +42,7 @@ echo namespace\foo::bar();
echo namespace\f1();
echo namespace\f2();
echo namespace\f3(new namespace\foo());
echo namespace\unknown;
?>
--EXPECTF--
const ok
@ -54,3 +55,5 @@ const ok
const ok
class ok
ok
Fatal error: Undefined constant 'Test\ns1\unknown' in %sns_057.php on line %d

View File

@ -40,8 +40,9 @@ echo namespace\foo::bar();
echo namespace\f1();
echo namespace\f2();
echo namespace\f3(new namespace\foo());
echo namespace\unknown;
?>
--EXPECT--
--EXPECTF--
const ok
func ok
const ok
@ -52,3 +53,5 @@ const ok
const ok
class ok
ok
Fatal error: Undefined constant 'unknown' in %sns_058.php on line %d

View File

@ -11,7 +11,7 @@ class bar {
}
}
new bar(new stdclass);
new bar(new \stdclass);
new bar(null);
?>

View File

@ -12,7 +12,7 @@ class bar {
}
new bar(null);
new bar(new stdclass);
new bar(new \stdclass);
?>
--EXPECTF--

View File

@ -22,7 +22,7 @@ class test implements foo {
new bar(new test);
new bar(null);
new bar(new stdclass);
new bar(new \stdclass);
?>
--EXPECTF--

View File

@ -11,12 +11,9 @@ $x = function (\stdclass $x = NULL) {
$x(NULL);
$x(new \stdclass);
$x(new stdclass);
?>
--EXPECTF--
NULL
object(stdClass)#%d (0) {
}
object(stdClass)#%d (0) {
}

View File

@ -9,16 +9,16 @@ $x = function (\stdclass $x = NULL) {
var_dump($x);
};
class stdclass { }
class stdclass extends \stdclass { }
$x(NULL);
$x(new stdclass);
$x(new stdclass);
$x(new \stdclass);
?>
--EXPECTF--
NULL
object(foo\stdClass)#%d (0) {
object(foo\stdclass)#%d (0) {
}
object(foo\stdClass)#%d (0) {
object(stdClass)#%d (0) {
}

View File

@ -516,7 +516,7 @@ typedef int (*zend_write_func_t)(const char *str, uint str_length);
/* Ugly hack to support constants as static array indices */
#define IS_CONSTANT_TYPE_MASK 0x0f
#define IS_CONSTANT_RT_NS_CHECK 0x10
#define IS_CONSTANT_UNQUALIFIED 0x10
#define IS_CONSTANT_INDEX 0x80
#define IS_LEXICAL_VAR 0x20
#define IS_LEXICAL_REF 0x40

View File

@ -1535,42 +1535,28 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace
zend_function *function;
char *lcname;
int prefix_len = 0;
char *is_compound = NULL;
char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant));
if (Z_STRVAL(function_name->u.constant)[0] == '\\') {
is_compound = memchr(Z_STRVAL(function_name->u.constant)+1, '\\', Z_STRLEN(function_name->u.constant)-1);
} else {
is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant));
}
if (check_namespace) {
ulong unused;
zend_resolve_non_class_name(function_name, check_namespace TSRMLS_CC);
zend_resolve_non_class_name(function_name, &unused, 2, 1 TSRMLS_CC);
if (Z_STRVAL(function_name->u.constant)[0] == '\\') {
memmove(Z_STRVAL(function_name->u.constant), Z_STRVAL(function_name->u.constant)+1, Z_STRLEN(function_name->u.constant));
--Z_STRLEN(function_name->u.constant);
}
if (CG(current_namespace) && !is_compound) {
if (check_namespace && CG(current_namespace) && !is_compound) {
/* We assume we call function from the current namespace
if it is not prefixed. */
/* In run-time PHP will check for function with full name and
internal function with short name */
prefix_len = Z_STRLEN_P(CG(current_namespace)) + 1;
}
} else if (Z_STRVAL(function_name->u.constant)[0] == '\\') {
memmove(Z_STRVAL(function_name->u.constant), Z_STRVAL(function_name->u.constant)+1, Z_STRLEN(function_name->u.constant));
--Z_STRLEN(function_name->u.constant);
}
zend_do_begin_dynamic_function_call(function_name, 1 TSRMLS_CC);
return 1;
}
lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len);
if ((zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+1, (void **) &function)==FAILURE) ||
((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS) &&
(function->type == ZEND_INTERNAL_FUNCTION))) {
zend_do_begin_dynamic_function_call(function_name, prefix_len TSRMLS_CC);
efree(lcname);
return 1; /* Dynamic */
}
((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS) &&
(function->type == ZEND_INTERNAL_FUNCTION))) {
zend_do_begin_dynamic_function_call(function_name, 0 TSRMLS_CC);
efree(lcname);
return 1; /* Dynamic */
}
efree(function_name->u.constant.value.str.val);
function_name->u.constant.value.str.val = lcname;
@ -1636,14 +1622,14 @@ void zend_do_clone(znode *result, const znode *expr TSRMLS_DC)
}
void zend_do_begin_dynamic_function_call(znode *function_name, int prefix_len TSRMLS_DC)
void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRMLS_DC)
{
unsigned char *ptr = NULL;
zend_op *opline;
zend_op *opline, *opline2;
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
if (prefix_len) {
if (ns_call) {
char *slash;
/* In run-time PHP will check for function with full name and
internal function with short name */
opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
@ -1654,15 +1640,18 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int prefix_len TS
Z_STRVAL(opline->op1.u.constant) = zend_str_tolower_dup(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant));
Z_STRLEN(opline->op1.u.constant) = Z_STRLEN(opline->op2.u.constant);
opline->extended_value = zend_hash_func(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant) + 1);
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_OP_DATA;
opline->op1.op_type = IS_CONST;
Z_TYPE(opline->op1.u.constant) = IS_STRING;
Z_STRLEN(opline->op1.u.constant) = Z_STRLEN(function_name->u.constant) - prefix_len;
Z_STRVAL(opline->op1.u.constant) = zend_str_tolower_dup(Z_STRVAL(function_name->u.constant) + prefix_len, Z_STRLEN(opline->op1.u.constant));
opline->op2.op_type = IS_CONST;
ZVAL_BOOL(&opline->op2.u.constant, (memchr(Z_STRVAL(opline->op1.u.constant), '\\', Z_STRLEN(opline->op1.u.constant)) != NULL));
opline->extended_value = zend_hash_func(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant) + 1);
opline2 = get_next_op(CG(active_op_array) TSRMLS_CC);
opline2->opcode = ZEND_OP_DATA;
opline2->op1.op_type = IS_CONST;
Z_TYPE(opline2->op1.u.constant) = IS_LONG;
slash = zend_memrchr(Z_STRVAL(opline->op1.u.constant), '\\', Z_STRLEN(opline->op1.u.constant));
if(!slash) {
zend_error(E_CORE_ERROR, "Namespaced name %s should contain slash", Z_STRVAL(opline->op1.u.constant));
}
/* this is the length of namespace prefix */
Z_LVAL(opline2->op1.u.constant) = slash-Z_STRVAL(opline->op1.u.constant)+1;
/* this is the hash of the non-prefixed part, lowercased */
opline2->extended_value = zend_hash_func(slash+1, Z_STRLEN(opline->op1.u.constant)-Z_LVAL(opline2->op1.u.constant)+1);
} else {
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
opline->op2 = *function_name;
@ -1678,34 +1667,33 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int prefix_len TS
}
}
zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
zend_do_extended_fcall_begin(TSRMLS_C);
}
/* type = 1 for constant, 2 for function */
void zend_resolve_non_class_name(znode *element_name, ulong *fetch_type, int type, int check_namespace TSRMLS_DC)
void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace TSRMLS_DC)
{
znode tmp;
int len;
zval **ns;
char *lcname, *check_import = memchr(Z_STRVAL(element_name->u.constant), '\\', Z_STRLEN(element_name->u.constant));
char *lcname, *compound = memchr(Z_STRVAL(element_name->u.constant), '\\', Z_STRLEN(element_name->u.constant));
if (Z_STRVAL(element_name->u.constant)[0] == '\\') {
check_namespace = 0;
check_import = 0;
/* name starts with \ so it is known and unambiguos, nothing to do here but shorten it */
memmove(Z_STRVAL(element_name->u.constant), Z_STRVAL(element_name->u.constant)+1, Z_STRLEN(element_name->u.constant));
--Z_STRLEN(element_name->u.constant);
return;
}
if (check_import && CG(current_import)) {
len = check_import - Z_STRVAL(element_name->u.constant);
if(!check_namespace) {
return;
}
if (compound && CG(current_import)) {
len = compound - Z_STRVAL(element_name->u.constant);
lcname = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len);
/* Check if first part of compound name is an import name */
if (zend_hash_find(CG(current_import), lcname, len+1, (void**)&ns) == SUCCESS) {
if (!check_import && type == 1) {
/* tell zend_get_constant_ex this is an ambiguous T_STRING */
*fetch_type |= IS_CONSTANT_RT_NS_CHECK;
}
/* Substitute import name */
tmp.op_type = IS_CONST;
tmp.u.constant = **ns;
@ -1714,22 +1702,14 @@ void zend_resolve_non_class_name(znode *element_name, ulong *fetch_type, int typ
Z_STRLEN(element_name->u.constant) -= len;
memmove(Z_STRVAL(element_name->u.constant), Z_STRVAL(element_name->u.constant)+len, Z_STRLEN(element_name->u.constant)+1);
zend_do_build_namespace_name(&tmp, &tmp, element_name TSRMLS_CC);
if (Z_STRVAL(tmp.u.constant)[0] != '\\') {
/* make this a \global\namespaced\element */
znode global;
zend_do_build_namespace_name(&global, NULL, &tmp TSRMLS_CC);
*element_name = global;
} else {
*element_name = tmp;
}
*element_name = tmp;
efree(lcname);
return;
}
efree(lcname);
}
if (check_namespace && CG(current_namespace)) {
if (CG(current_namespace)) {
tmp = *element_name;
Z_STRLEN(tmp.u.constant) = sizeof("\\")-1 + Z_STRLEN(element_name->u.constant) + Z_STRLEN_P(CG(current_namespace));
Z_STRVAL(tmp.u.constant) = (char *) emalloc(Z_STRLEN(tmp.u.constant)+1);
@ -1738,11 +1718,6 @@ void zend_resolve_non_class_name(znode *element_name, ulong *fetch_type, int typ
memcpy(&(Z_STRVAL(tmp.u.constant)[Z_STRLEN_P(CG(current_namespace)) + sizeof("\\")-1]), Z_STRVAL(element_name->u.constant), Z_STRLEN(element_name->u.constant)+1);
STR_FREE(Z_STRVAL(element_name->u.constant));
*element_name = tmp;
if (type == 1) {
/* We assume we use constant from the current namespace
if it is not prefixed. */
*fetch_type |= IS_CONSTANT_RT_NS_CHECK;
}
}
}
@ -1757,8 +1732,7 @@ void zend_resolve_class_name(znode *class_name, ulong *fetch_type, int check_ns_
compound = memchr(Z_STRVAL(class_name->u.constant), '\\', Z_STRLEN(class_name->u.constant));
if (compound) {
/* This is a compound class name that contains namespace prefix */
if (Z_TYPE(class_name->u.constant) == IS_STRING &&
Z_STRVAL(class_name->u.constant)[0] == '\\') {
if (Z_STRVAL(class_name->u.constant)[0] == '\\') {
/* The STRING name has "\" prefix */
Z_STRLEN(class_name->u.constant) -= 1;
memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+1, Z_STRLEN(class_name->u.constant)+1);
@ -1784,11 +1758,12 @@ void zend_resolve_class_name(znode *class_name, ulong *fetch_type, int check_ns_
memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+len, Z_STRLEN(class_name->u.constant)+1);
zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
*class_name = tmp;
efree(lcname);
return;
}
efree(lcname);
return;
}
/* Here name is not prefixed with \ and not imported */
if (CG(current_namespace)) {
tmp.op_type = IS_CONST;
tmp.u.constant = *CG(current_namespace);
@ -1808,23 +1783,7 @@ void zend_resolve_class_name(znode *class_name, ulong *fetch_type, int check_ns_
class_name->u.constant = **ns;
zval_copy_ctor(&class_name->u.constant);
} else if (CG(current_namespace)) {
zend_class_entry **pce;
if (check_ns_name) {
/* PHP will need to perform additional checks at run-time to
determine if we assume namespace or class name. */
*fetch_type |= ZEND_FETCH_CLASS_RT_NS_NAME;
}
if ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) ||
(zend_hash_find(CG(class_table), lcname, Z_STRLEN(class_name->u.constant)+1, (void**)&pce) == SUCCESS &&
(*pce)->type == ZEND_INTERNAL_CLASS)) {
/* There is an internal class with the same name exists.
PHP will need to perform additional cheks at run-time to
determine if we assume class in current namespace or
internal one. */
*fetch_type |= ZEND_FETCH_CLASS_RT_NS_CHECK;
}
/* plain name, no import - prepend current namespace to it */
tmp.op_type = IS_CONST;
tmp.u.constant = *CG(current_namespace);
zval_copy_ctor(&tmp.u.constant);
@ -2059,7 +2018,6 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
}
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
opline->extended_value = fetch_type & ~ZEND_FETCH_CLASS_RT_NS_NAME;
opline->op1 = class_node;
opline->op2 = *method_name;
@ -2077,11 +2035,6 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na
nsname = Z_STRVAL(class_node.u.constant);
nsname_len = Z_STRLEN(class_node.u.constant);
if (fetch_type & ZEND_FETCH_CLASS_RT_NS_NAME) {
/* Remove namespace name */
nsname = (char *)memchr(nsname, '\\', nsname_len) + 1;
nsname_len -= (nsname - Z_STRVAL(class_node.u.constant));
}
len = nsname_len + 1 + Z_STRLEN(method_name->u.constant);
fname = emalloc(len + 1);
memcpy(fname, nsname, nsname_len);
@ -3924,9 +3877,9 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con
znode tmp;
zend_op *opline;
int type;
char *check_import;
char *compound;
ulong fetch_type = 0;
int unknown_should_fatal = 0;
int unknown_should_fail = 0;
if (constant_container) {
switch (mode) {
@ -3955,7 +3908,6 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con
opline->opcode = ZEND_FETCH_CONSTANT;
opline->result.op_type = IS_TMP_VAR;
opline->result.u.var = get_temporary_variable(CG(active_op_array));
opline->extended_value = fetch_type & ~ZEND_FETCH_CLASS_RT_NS_NAME;
opline->op1 = *constant_container;
opline->op2 = *constant_name;
*result = opline->result;
@ -3964,100 +3916,46 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con
return;
}
/* namespace constant */
/* only one that did not contain \ from the start can be converted to string if unknown */
switch (mode) {
case ZEND_CT:
if (check_namespace == 2) {
unknown_should_fatal = 1;
check_namespace = 0;
}
type = zend_get_class_fetch_type(Z_STRVAL(constant_name->u.constant), Z_STRLEN(constant_name->u.constant));
check_import = memchr(Z_STRVAL(constant_name->u.constant), '\\', Z_STRLEN(constant_name->u.constant));
compound = memchr(Z_STRVAL(constant_name->u.constant), '\\', Z_STRLEN(constant_name->u.constant));
/* this is a namespace constant, or an unprefixed constant */
if (Z_STRVAL(constant_name->u.constant)[0] == '\\') {
check_namespace = 0;
if (memchr(Z_STRVAL(constant_name->u.constant)+1, '\\', Z_STRLEN(constant_name->u.constant)-1)) {
/* tell engine this is an explicit namespaced constant, which
results in fatal error if constant not found, see
zend_execute_API.c::zval_update_constant_ex() */
unknown_should_fatal = 1;
}
check_import = 0;
} else if (check_import) {
unknown_should_fatal = 1;
}
if (ZEND_FETCH_CLASS_STATIC == type) {
zend_error(E_ERROR, "\"static\\\" is not allowed in compile-time constants");
}
zend_resolve_non_class_name(constant_name, &fetch_type, 1, check_namespace TSRMLS_CC);
if (zend_constant_ct_subst(result, &constant_name->u.constant, 0 TSRMLS_CC)) {
break;
}
fetch_type &= IS_CONSTANT_RT_NS_CHECK;
if (unknown_should_fatal) {
fetch_type |= ZEND_FETCH_CLASS_RT_NS_CHECK;
zend_resolve_non_class_name(constant_name, check_namespace TSRMLS_CC);
if(!compound) {
fetch_type |= IS_CONSTANT_UNQUALIFIED;
}
*result = *constant_name;
result->u.constant.type = IS_CONSTANT | fetch_type;
break;
case ZEND_RT:
/* this is a namespace constant, or an unprefixed constant */
/* check_namespace = 2 means namespace\ prefix passed in */
/* check_namespace = 0 means \constant\name passed in */
/* check_namespace = 1 means constant\name passed in or name passed in */
compound = memchr(Z_STRVAL(constant_name->u.constant), '\\', Z_STRLEN(constant_name->u.constant));
if (check_namespace == 2) {
unknown_should_fatal = 1;
check_namespace = 0;
}
type = zend_get_class_fetch_type(Z_STRVAL(constant_name->u.constant), Z_STRLEN(constant_name->u.constant));
if (ZEND_FETCH_CLASS_STATIC == type) {
zend_error(E_ERROR, "\"static::\" is not allowed in compile-time constants");
zend_resolve_non_class_name(constant_name, check_namespace TSRMLS_CC);
if(zend_constant_ct_subst(result, &constant_name->u.constant, 1 TSRMLS_CC)) {
break;
}
if (Z_STRVAL(constant_name->u.constant)[0] == '\\') {
check_namespace = 0;
check_import = 0;
if (memchr(Z_STRVAL(constant_name->u.constant)+1, '\\', Z_STRLEN(constant_name->u.constant)-1)) {
/* tell engine this is an explicit namespaced constant, which
results in fatal error if constant not found */
unknown_should_fatal = 1;
}
/* we can only check for compile-time if the constant is explicitly
\top\level */
check_compile_time:
if (zend_constant_ct_subst(result, &constant_name->u.constant, 1 TSRMLS_CC)) {
break;
}
} else {
check_import = memchr(Z_STRVAL(constant_name->u.constant), '\\', Z_STRLEN(constant_name->u.constant));
if (check_import) {
unknown_should_fatal = 1;
}
if (!check_namespace || !CG(current_namespace)) {
goto check_compile_time;
}
}
/* we reach here if the constant name is ambiguous (not \this) */
/* we will store nsname and <whatever>, where
<whatever> is the actual constant name passed in (foo or foo/foo)
and ZEND_FETCH_CONSTANT will first look for nsname/<whatever> and then
<whatever> after current_import is applied to <whatever> */
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
if (unknown_should_fatal) {
fetch_type = ZEND_FETCH_CLASS_RT_NS_CHECK;
}
opline->opcode = ZEND_FETCH_CONSTANT;
opline->result.op_type = IS_TMP_VAR;
opline->result.u.var = get_temporary_variable(CG(active_op_array));
*result = opline->result;
SET_UNUSED(opline->op1);
zend_resolve_non_class_name(constant_name, &fetch_type, 1, check_namespace TSRMLS_CC);
opline->extended_value = fetch_type;
if(compound) {
/* the name is unambiguous */
opline->extended_value = 0;
} else {
opline->extended_value = IS_CONSTANT_UNQUALIFIED;
}
opline->op2 = *constant_name;
break;
}
@ -5308,7 +5206,7 @@ void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC) /* {{{ */
}
if (CG(current_namespace)) {
/* Prefix constant name with name of current namespace */
/* Prefix constant name with name of current namespace, lowercased */
znode tmp;
tmp.op_type = IS_CONST;

View File

@ -359,7 +359,7 @@ ZEND_API char *zend_get_compiled_filename(TSRMLS_D);
ZEND_API int zend_get_compiled_lineno(TSRMLS_D);
ZEND_API size_t zend_get_scanned_file_offset(TSRMLS_D);
void zend_resolve_non_class_name(znode *element_name, ulong *fetch_type, int type, int check_namespace TSRMLS_DC);
void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace TSRMLS_DC);
void zend_resolve_class_name(znode *class_name, ulong *fetch_type, int check_ns_name TSRMLS_DC);
ZEND_API char* zend_get_compiled_variable_name(const zend_op_array *op_array, zend_uint var, int* name_len);
@ -636,8 +636,6 @@ int zendlex(znode *zendlval TSRMLS_DC);
#define ZEND_FETCH_CLASS_INTERFACE 6
#define ZEND_FETCH_CLASS_STATIC 7
#define ZEND_FETCH_CLASS_MASK 0x0f
#define ZEND_FETCH_CLASS_RT_NS_CHECK 0x20
#define ZEND_FETCH_CLASS_RT_NS_NAME 0x40
#define ZEND_FETCH_CLASS_NO_AUTOLOAD 0x80
#define ZEND_FETCH_CLASS_SILENT 0x0100

View File

@ -281,11 +281,10 @@ ZEND_API int zend_get_constant_ex(const char *name, uint name_len, zval *result,
char *class_name;
zval **ret_constant;
/* Skip leading :: */
/* Skip leading \\ */
if (name[0] == '\\') {
name += 1;
name_len -= 1;
flags &= ZEND_FETCH_CLASS_SILENT;
}
@ -335,10 +334,7 @@ ZEND_API int zend_get_constant_ex(const char *name, uint name_len, zval *result,
efree(lcname);
} else {
efree(lcname);
if ((flags & IS_CONSTANT_RT_NS_CHECK) == 0) {
/* Check for class */
ce = zend_fetch_class(class_name, class_name_len, flags TSRMLS_CC);
}
ce = zend_fetch_class(class_name, class_name_len, flags TSRMLS_CC);
}
if (retval && ce) {
if (zend_hash_find(&ce->constants_table, constant_name, const_name_len+1, (void **) &ret_constant) != SUCCESS) {
@ -350,34 +346,28 @@ ZEND_API int zend_get_constant_ex(const char *name, uint name_len, zval *result,
} else if (!ce) {
retval = 0;
}
efree(class_name);
goto finish;
}
if ((colon = zend_memrchr(name, '\\', name_len)) &&
colon > name) {
/* non-class constant */
if ((colon = zend_memrchr(name, '\\', name_len)) != NULL) {
/* compound constant name */
int class_name_len = colon - name;
int const_name_len = name_len - class_name_len - 1;
int prefix_len = colon - name;
int const_name_len = name_len - prefix_len - 1;
char *constant_name = colon + 1;
char *lcname;
char *nsname;
unsigned int nsname_len;
class_name = estrndup(name, class_name_len);
lcname = zend_str_tolower_dup(class_name, class_name_len);
lcname = zend_str_tolower_dup(name, prefix_len);
/* Check for namespace constant */
/* Concatenate lowercase namespace name and constant name */
lcname = erealloc(lcname, class_name_len + 1 + const_name_len + 1);
lcname[class_name_len] = '\\';
memcpy(lcname + class_name_len + 1, constant_name, const_name_len + 1);
lcname = erealloc(lcname, prefix_len + 1 + const_name_len + 1);
lcname[prefix_len] = '\\';
memcpy(lcname + prefix_len + 1, constant_name, const_name_len + 1);
nsname = lcname;
nsname_len = class_name_len + 1 + const_name_len;
if (zend_hash_find(EG(zend_constants), nsname, nsname_len+1, (void **) &c) == SUCCESS) {
if (zend_hash_find(EG(zend_constants), lcname, prefix_len + 1 + const_name_len + 1, (void **) &c) == SUCCESS) {
efree(lcname);
efree(class_name);
*result = c->value;
zval_update_constant_ex(&result, (void*)1, NULL TSRMLS_CC);
zval_copy_ctor(result);
@ -387,17 +377,14 @@ ZEND_API int zend_get_constant_ex(const char *name, uint name_len, zval *result,
}
efree(lcname);
if ((flags & IS_CONSTANT_RT_NS_CHECK) != 0) {
/* name requires runtime resolution, need to check non-namespaced name */
if ((flags & IS_CONSTANT_UNQUALIFIED) != 0) {
name = constant_name;
name_len = const_name_len;
efree(class_name);
return zend_get_constant(name, name_len, result TSRMLS_CC);
}
retval = 0;
finish:
efree(class_name);
if (retval) {
zval_update_constant_ex(ret_constant, (void*)1, ce TSRMLS_CC);
*result = **ret_constant;

View File

@ -519,7 +519,7 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *sco
} else {
char *save = actual;
int actual_len = Z_STRLEN_P(p);
if (Z_TYPE_P(p) & IS_CONSTANT_RT_NS_CHECK) {
if (Z_TYPE_P(p) & IS_CONSTANT_UNQUALIFIED) {
actual = (char *)zend_memrchr(actual, '\\', actual_len) + 1;
actual_len -= (actual - Z_STRVAL_P(p));
if (inline_change) {
@ -537,7 +537,7 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *sco
}
--actual_len;
}
if (Z_TYPE_P(p) & ZEND_FETCH_CLASS_RT_NS_CHECK) {
if ((Z_TYPE_P(p) & IS_CONSTANT_UNQUALIFIED) == 0) {
int fix_save = 0;
if (save[0] == '\\') {
save++;
@ -612,7 +612,7 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *sco
str_index_len -= ((colon - str_index) + 1);
str_index = colon;
} else {
if (str_index[str_index_len - 2] & IS_CONSTANT_RT_NS_CHECK) {
if (str_index[str_index_len - 2] & IS_CONSTANT_UNQUALIFIED) {
actual = (char *)zend_memrchr(str_index, '\\', str_index_len - 3) + 1;
str_index_len -= (actual - str_index);
str_index = actual;
@ -624,7 +624,7 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *sco
if (save[0] == '\\') {
++save;
}
if (str_index[str_index_len - 2] & ZEND_FETCH_CLASS_RT_NS_CHECK) {
if ((str_index[str_index_len - 2] & IS_CONSTANT_UNQUALIFIED) == 0) {
zend_error(E_ERROR, "Undefined constant '%s'", save);
}
zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", str_index, str_index);
@ -1472,7 +1472,6 @@ zend_class_entry *zend_fetch_class(const char *class_name, uint class_name_len,
{
zend_class_entry **pce;
int use_autoload = (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) == 0;
int rt_ns_check = (fetch_type & ZEND_FETCH_CLASS_RT_NS_CHECK) ? 1 : 0;
int silent = (fetch_type & ZEND_FETCH_CLASS_SILENT) != 0;
fetch_type &= ZEND_FETCH_CLASS_MASK;
@ -1506,36 +1505,14 @@ check_fetch_type:
break;
}
if (zend_lookup_class_ex(class_name, class_name_len, (!rt_ns_check & use_autoload), &pce TSRMLS_CC) == FAILURE) {
if (rt_ns_check) {
/* Check if we have internal class with the same name */
char *php_name;
uint php_name_len;
php_name = zend_memrchr(class_name, '\\', class_name_len);
if (php_name) {
php_name++;
php_name_len = class_name_len - (php_name - class_name);
php_name = zend_str_tolower_dup(php_name, php_name_len);
if (zend_hash_find(EG(class_table), php_name, php_name_len + 1, (void **) &pce) == SUCCESS &&
(*pce)->type == ZEND_INTERNAL_CLASS
) {
efree(php_name);
return *pce;
}
efree(php_name);
}
}
if (zend_lookup_class_ex(class_name, class_name_len, use_autoload, &pce TSRMLS_CC) == FAILURE) {
if (use_autoload) {
if (rt_ns_check && zend_lookup_class_ex(class_name, class_name_len, 1, &pce TSRMLS_CC) == SUCCESS) {
return *pce;
}
if (!silent && !EG(exception)) {
if (fetch_type == ZEND_FETCH_CLASS_INTERFACE) {
zend_error(E_ERROR, "Interface '%s' not found", class_name);
} else {
zend_error(E_ERROR, "Class '%s' not found", class_name);
}
}
}
}
return NULL;

View File

@ -769,7 +769,7 @@ common_scalar:
static_scalar: /* compile-time evaluated scalars */
common_scalar { $$ = $1; }
| namespace_name { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT, 1 TSRMLS_CC); }
| T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_CT, 2 TSRMLS_CC); }
| T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_CT, 0 TSRMLS_CC); }
| T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); memcpy(&(tmp[1]), Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); tmp[0] = '\\'; efree(Z_STRVAL($2.u.constant)); Z_STRVAL($2.u.constant) = tmp; ++Z_STRLEN($2.u.constant); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_CT, 0 TSRMLS_CC); }
| '+' static_scalar { ZVAL_LONG(&$1.u.constant, 0); add_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; }
| '-' static_scalar { ZVAL_LONG(&$1.u.constant, 0); sub_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; }
@ -778,14 +778,14 @@ static_scalar: /* compile-time evaluated scalars */
;
static_class_constant:
class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_CT, 2 TSRMLS_CC); }
class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_CT, 0 TSRMLS_CC); }
;
scalar:
T_STRING_VARNAME { $$ = $1; }
| class_constant { $$ = $1; }
| namespace_name { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT, 1 TSRMLS_CC); }
| T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_RT, 2 TSRMLS_CC); }
| T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_RT, 0 TSRMLS_CC); }
| T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); memcpy(&(tmp[1]), Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); tmp[0] = '\\'; efree(Z_STRVAL($2.u.constant)); Z_STRVAL($2.u.constant) = tmp; ++Z_STRLEN($2.u.constant); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_RT, 0 TSRMLS_CC); }
| common_scalar { $$ = $1; }
| '"' encaps_list '"' { $$ = $2; }
@ -993,7 +993,7 @@ isset_variables:
;
class_constant:
class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT, 2 TSRMLS_CC); }
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); }
;

View File

@ -2108,8 +2108,8 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST)
zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
if (zend_hash_quick_find(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc))==FAILURE) {
if (zend_hash_quick_find(EG(function_table), Z_STRVAL(op_data->op1.u.constant), Z_STRLEN(op_data->op1.u.constant)+1, op_data->extended_value, (void **) &EX(fbc))==FAILURE ||
(Z_BVAL(op_data->op2.u.constant) && EX(fbc)->type != ZEND_INTERNAL_FUNCTION)) {
char *short_name = Z_STRVAL(opline->op1.u.constant)+Z_LVAL(op_data->op1.u.constant);
if (zend_hash_quick_find(EG(function_table), short_name, Z_STRLEN(opline->op1.u.constant)-Z_LVAL(op_data->op1.u.constant)+1, op_data->extended_value, (void **) &EX(fbc))==FAILURE) {
zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL(opline->op2.u.constant));
}
}
@ -2974,39 +2974,21 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, CONST)
if (OP1_TYPE == IS_UNUSED) {
/* namespaced constant */
if (!zend_get_constant_ex(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var, NULL, opline->extended_value TSRMLS_CC)) {
char *actual = Z_STRVAL(opline->op2.u.constant);
if (opline->extended_value & IS_CONSTANT_RT_NS_CHECK) {
actual = (char *)zend_memrchr(actual, '\\', Z_STRLEN(opline->op2.u.constant)) + 1;
Z_STRLEN(opline->op2.u.constant) -= (actual - Z_STRVAL(opline->op2.u.constant));
actual = estrndup(actual, Z_STRLEN(opline->op2.u.constant));
efree(Z_STRVAL(opline->op2.u.constant));
Z_STRVAL(opline->op2.u.constant) = actual;
}
if (Z_STRVAL(opline->op2.u.constant)[0] == '\\') {
if (opline->extended_value & ZEND_FETCH_CLASS_RT_NS_CHECK) {
zend_error_noreturn(E_ERROR, "Undefined constant '%s'",
Z_STRVAL(opline->op2.u.constant)+1,
Z_STRVAL(opline->op2.u.constant)+1);
if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {
char *actual = (char *)zend_memrchr(Z_STRVAL(opline->op2.u.constant), '\\', Z_STRLEN(opline->op2.u.constant));
if(!actual) {
actual = Z_STRVAL(opline->op2.u.constant);
} else {
actual++;
}
zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'",
Z_STRVAL(opline->op2.u.constant)+1,
Z_STRVAL(opline->op2.u.constant)+1);
EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;
++Z_STRVAL(EX_T(opline->result.u.var).tmp_var);
--Z_STRLEN(EX_T(opline->result.u.var).tmp_var);
/* non-qualified constant - allow text substitution */
zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", actual, actual);
ZVAL_STRING(&EX_T(opline->result.u.var).tmp_var, actual, Z_STRLEN(opline->op2.u.constant)-(actual - Z_STRVAL(opline->op2.u.constant)));
zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
} else {
if (opline->extended_value & ZEND_FETCH_CLASS_RT_NS_CHECK) {
zend_error_noreturn(E_ERROR, "Undefined constant '%s'",
Z_STRVAL(opline->op2.u.constant),
Z_STRVAL(opline->op2.u.constant));
}
zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'",
Z_STRVAL(opline->op2.u.constant),
Z_STRVAL(opline->op2.u.constant));
EX_T(opline->result.u.var).tmp_var = opline->op2.u.constant;
zend_error_noreturn(E_ERROR, "Undefined constant '%s'",
Z_STRVAL(opline->op2.u.constant), Z_STRVAL(opline->op2.u.constant));
}
zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var);
}
ZEND_VM_NEXT_OPCODE();
} else {

File diff suppressed because it is too large Load Diff