diff options
author | Dmitry Stogov <dmitry@php.net> | 2007-09-28 19:52:53 +0000 |
---|---|---|
committer | Dmitry Stogov <dmitry@php.net> | 2007-09-28 19:52:53 +0000 |
commit | f32ffe9b430b718628f868e449c1fcbdc8ec9ef6 (patch) | |
tree | d46f435df40bcfe67bbab884f612a3551448431e | |
parent | 1674976346b5d8294eae99ec395f101f14405e2d (diff) | |
download | php-git-f32ffe9b430b718628f868e449c1fcbdc8ec9ef6.tar.gz |
Namespaces
72 files changed, 3139 insertions, 664 deletions
@@ -1,6 +1,7 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? 20??, PHP 5.3.0 +- Added support for namespaces. (Dmitry, Stas) - Added support for dynamic access of static members using $foo::myFunc(). (Etienne Kneuss) diff --git a/Zend/tests/ns_001.phpt b/Zend/tests/ns_001.phpt new file mode 100755 index 0000000000..6821756a43 --- /dev/null +++ b/Zend/tests/ns_001.phpt @@ -0,0 +1,34 @@ +--TEST-- +001: Class in namespace +--FILE-- +<?php +namespace test::ns1; + +class Foo { + + function __construct() { + echo __CLASS__,"\n"; + } + + function bar() { + echo __CLASS__,"\n"; + } + + static function baz() { + echo __CLASS__,"\n"; + } +} + +$x = new Foo; +$x->bar(); +Foo::baz(); +$y = new test::ns1::Foo; +$y->bar(); +test::ns1::Foo::baz(); +--EXPECT-- +test::ns1::Foo +test::ns1::Foo +test::ns1::Foo +test::ns1::Foo +test::ns1::Foo +test::ns1::Foo diff --git a/Zend/tests/ns_002.phpt b/Zend/tests/ns_002.phpt new file mode 100755 index 0000000000..4b17012a94 --- /dev/null +++ b/Zend/tests/ns_002.phpt @@ -0,0 +1,27 @@ +--TEST-- +002: Import in namespace +--FILE-- +<?php +namespace test::ns1; + +class Foo { + static function bar() { + echo __CLASS__,"\n"; + } +} + +import test::ns1::Foo as Bar; +import test::ns1 as ns2; +import test::ns1; + +Foo::bar(); +test::ns1::Foo::bar(); +Bar::bar(); +ns2::Foo::bar(); +ns1::Foo::bar(); +--EXPECT-- +test::ns1::Foo +test::ns1::Foo +test::ns1::Foo +test::ns1::Foo +test::ns1::Foo diff --git a/Zend/tests/ns_003.phpt b/Zend/tests/ns_003.phpt new file mode 100755 index 0000000000..26c21a9ff0 --- /dev/null +++ b/Zend/tests/ns_003.phpt @@ -0,0 +1,12 @@ +--TEST-- +003: Name conflict (ns name) +--FILE-- +<?php +namespace test::ns1; + +class Exception { +} + +echo get_class(new Exception()),"\n"; +--EXPECT-- +test::ns1::Exception diff --git a/Zend/tests/ns_004.phpt b/Zend/tests/ns_004.phpt new file mode 100755 index 0000000000..2aa4a809d9 --- /dev/null +++ b/Zend/tests/ns_004.phpt @@ -0,0 +1,9 @@ +--TEST-- +004: Name conflict (php name) +--FILE-- +<?php +namespace test::ns1; + +echo get_class(new Exception()),"\n"; +--EXPECT-- +Exception diff --git a/Zend/tests/ns_005.phpt b/Zend/tests/ns_005.phpt new file mode 100755 index 0000000000..fc1d6570fd --- /dev/null +++ b/Zend/tests/ns_005.phpt @@ -0,0 +1,12 @@ +--TEST-- +005: Name conflict (php name in case if ns name exists) +--FILE-- +<?php +namespace test::ns1; + +class Exception { +} + +echo get_class(new ::Exception()),"\n"; +--EXPECT-- +Exception diff --git a/Zend/tests/ns_006.phpt b/Zend/tests/ns_006.phpt new file mode 100755 index 0000000000..f4027408d4 --- /dev/null +++ b/Zend/tests/ns_006.phpt @@ -0,0 +1,13 @@ +--TEST-- +006: Run-time name conflict (ns name) +--FILE-- +<?php +namespace test::ns1; + +class Exception { +} + +$x = "test::ns1::Exception"; +echo get_class(new $x),"\n"; +--EXPECT-- +test::ns1::Exception diff --git a/Zend/tests/ns_007.phpt b/Zend/tests/ns_007.phpt new file mode 100755 index 0000000000..60ccced504 --- /dev/null +++ b/Zend/tests/ns_007.phpt @@ -0,0 +1,13 @@ +--TEST-- +007: Run-time name conflict (php name) +--FILE-- +<?php +namespace test::ns1; + +class Exception { +} + +$x = "Exception"; +echo get_class(new $x),"\n"; +--EXPECT-- +Exception diff --git a/Zend/tests/ns_008.phpt b/Zend/tests/ns_008.phpt new file mode 100755 index 0000000000..1c0d116483 --- /dev/null +++ b/Zend/tests/ns_008.phpt @@ -0,0 +1,13 @@ +--TEST-- +008: __NAMESPACE__ constant and runtime names (ns name) +--FILE-- +<?php +namespace test; + +class foo { +} + +$x = __NAMESPACE__ . "::foo"; +echo get_class(new $x),"\n"; +--EXPECT-- +test::foo diff --git a/Zend/tests/ns_009.phpt b/Zend/tests/ns_009.phpt new file mode 100755 index 0000000000..3d6aa225d6 --- /dev/null +++ b/Zend/tests/ns_009.phpt @@ -0,0 +1,11 @@ +--TEST-- +009: __NAMESPACE__ constant and runtime names (php name) +--FILE-- +<?php +class foo { +} + +$x = __NAMESPACE__ . "::foo"; +echo get_class(new $x),"\n"; +--EXPECT-- +foo diff --git a/Zend/tests/ns_010.phpt b/Zend/tests/ns_010.phpt new file mode 100755 index 0000000000..7be99e49bf --- /dev/null +++ b/Zend/tests/ns_010.phpt @@ -0,0 +1,49 @@ +--TEST-- +010: Accesing internal namespace class +--FILE-- +<?php +namespace X; +import X as Y; +class Foo { + const C = "const ok\n"; + static $var = "var ok\n"; + function __construct() { + echo "class ok\n"; + } + static function bar() { + echo "method ok\n"; + } +} +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 diff --git a/Zend/tests/ns_011.phpt b/Zend/tests/ns_011.phpt new file mode 100755 index 0000000000..c1d9ac3018 --- /dev/null +++ b/Zend/tests/ns_011.phpt @@ -0,0 +1,24 @@ +--TEST-- +011: Function in namespace +--FILE-- +<?php +namespace test::ns1; + +function foo() { + echo __FUNCTION__,"\n"; +} + +foo(); +test::ns1::foo(); +bar(); +test::ns1::bar(); + +function bar() { + echo __FUNCTION__,"\n"; +} + +--EXPECT-- +test::ns1::foo +test::ns1::foo +test::ns1::bar +test::ns1::bar diff --git a/Zend/tests/ns_012.phpt b/Zend/tests/ns_012.phpt new file mode 100755 index 0000000000..aa50661e79 --- /dev/null +++ b/Zend/tests/ns_012.phpt @@ -0,0 +1,35 @@ +--TEST-- +012: Import in namespace and functions +--FILE-- +<?php +namespace test::ns1; + +function foo() { + echo __FUNCTION__,"\n"; +} + +import test::ns1 as ns2; +import test as ns3; + +foo(); +bar(); +test::ns1::foo(); +test::ns1::bar(); +ns2::foo(); +ns2::bar(); +ns3::ns1::foo(); +ns3::ns1::bar(); + +function bar() { + echo __FUNCTION__,"\n"; +} + +--EXPECT-- +test::ns1::foo +test::ns1::bar +test::ns1::foo +test::ns1::bar +test::ns1::foo +test::ns1::bar +test::ns1::foo +test::ns1::bar diff --git a/Zend/tests/ns_013.phpt b/Zend/tests/ns_013.phpt new file mode 100755 index 0000000000..945b6bc4ec --- /dev/null +++ b/Zend/tests/ns_013.phpt @@ -0,0 +1,13 @@ +--TEST-- +013: Name conflict and functions (ns name) +--FILE-- +<?php +namespace test::ns1; + +function strlen($x) { + return __FUNCTION__; +} + +echo strlen("Hello"),"\n"; +--EXPECT-- +test::ns1::strlen diff --git a/Zend/tests/ns_014.phpt b/Zend/tests/ns_014.phpt new file mode 100755 index 0000000000..9614b481a4 --- /dev/null +++ b/Zend/tests/ns_014.phpt @@ -0,0 +1,9 @@ +--TEST-- +014: Name conflict and functions (php name) +--FILE-- +<?php +namespace test::ns1; + +echo strlen("Hello"),"\n"; +--EXPECT-- +5 diff --git a/Zend/tests/ns_015.phpt b/Zend/tests/ns_015.phpt new file mode 100755 index 0000000000..1ad05b963f --- /dev/null +++ b/Zend/tests/ns_015.phpt @@ -0,0 +1,14 @@ +--TEST-- +015: Name conflict and functions (php name in case if ns name exists) +--FILE-- +<?php +namespace test::ns1; + +function strlen($x) { + return __FUNCTION__; +} + +echo ::strlen("Hello"),"\n"; +--EXPECT-- +5 + diff --git a/Zend/tests/ns_016.phpt b/Zend/tests/ns_016.phpt new file mode 100755 index 0000000000..e278625e61 --- /dev/null +++ b/Zend/tests/ns_016.phpt @@ -0,0 +1,14 @@ +--TEST-- +016: Run-time name conflict and functions (ns name) +--FILE-- +<?php +namespace test::ns1; + +function strlen($x) { + return __FUNCTION__; +} + +$x = "test::ns1::strlen"; +echo $x("Hello"),"\n"; +--EXPECT-- +test::ns1::strlen diff --git a/Zend/tests/ns_017.phpt b/Zend/tests/ns_017.phpt new file mode 100755 index 0000000000..15ff1efee8 --- /dev/null +++ b/Zend/tests/ns_017.phpt @@ -0,0 +1,14 @@ +--TEST-- +017: Run-time name conflict and functions (php name) +--FILE-- +<?php +namespace test::ns1; + +function strlen($x) { + return __FUNCTION__; +} + +$x = "strlen"; +echo $x("Hello"),"\n"; +--EXPECT-- +5
\ No newline at end of file diff --git a/Zend/tests/ns_018.phpt b/Zend/tests/ns_018.phpt new file mode 100755 index 0000000000..be8b4b7d34 --- /dev/null +++ b/Zend/tests/ns_018.phpt @@ -0,0 +1,14 @@ +--TEST-- +018: __NAMESPACE__ constant and runtime names (ns name) +--FILE-- +<?php +namespace test; + +function foo() { + return __FUNCTION__; +} + +$x = __NAMESPACE__ . "::foo"; +echo $x(),"\n"; +--EXPECT-- +test::foo diff --git a/Zend/tests/ns_019.phpt b/Zend/tests/ns_019.phpt new file mode 100755 index 0000000000..c42e97ed18 --- /dev/null +++ b/Zend/tests/ns_019.phpt @@ -0,0 +1,12 @@ +--TEST-- +019: __NAMESPACE__ constant and runtime names (php name) +--FILE-- +<?php +function foo() { + return __FUNCTION__; +} + +$x = __NAMESPACE__ . "::foo"; +echo $x(),"\n"; +--EXPECT-- +foo diff --git a/Zend/tests/ns_020.phpt b/Zend/tests/ns_020.phpt new file mode 100755 index 0000000000..32325e09d2 --- /dev/null +++ b/Zend/tests/ns_020.phpt @@ -0,0 +1,18 @@ +--TEST-- +020: Accesing internal namespace function +--FILE-- +<?php +namespace X; +import X as Y; +function foo() { + echo __FUNCTION__,"\n"; +} +foo(); +X::foo(); +Y::foo(); +::X::foo(); +--EXPECT-- +X::foo +X::foo +X::foo +X::foo diff --git a/Zend/tests/ns_021.phpt b/Zend/tests/ns_021.phpt new file mode 100755 index 0000000000..01609bb607 --- /dev/null +++ b/Zend/tests/ns_021.phpt @@ -0,0 +1,23 @@ +--TEST-- +021: Name search priority (first look into namespace) +--FILE-- +<?php +namespace test; + +class Test { + static function foo() { + echo __CLASS__,"::",__FUNCTION__,"\n"; + } +} + +function foo() { + echo __FUNCTION__,"\n"; +} + +foo(); +test::foo(); +test::test::foo(); +--EXPECT-- +test::foo +test::foo +test::Test::foo diff --git a/Zend/tests/ns_022.inc b/Zend/tests/ns_022.inc new file mode 100755 index 0000000000..be571fc346 --- /dev/null +++ b/Zend/tests/ns_022.inc @@ -0,0 +1,6 @@ +<?php +class Test { + static function foo() { + echo __CLASS__,"::",__FUNCTION__,"\n"; + } +} diff --git a/Zend/tests/ns_022.phpt b/Zend/tests/ns_022.phpt new file mode 100755 index 0000000000..f46a856d01 --- /dev/null +++ b/Zend/tests/ns_022.phpt @@ -0,0 +1,19 @@ +--TEST-- +022: Name search priority (first look into import, then into current namespace and then for class) +--FILE-- +<?php +namespace a::b::c; + +import a::b::c as test; + +require "ns_022.inc"; + +function foo() { + echo __FUNCTION__,"\n"; +} + +test::foo(); +::test::foo(); +--EXPECT-- +a::b::c::foo +Test::foo diff --git a/Zend/tests/ns_023.phpt b/Zend/tests/ns_023.phpt new file mode 100755 index 0000000000..4be9dc700a --- /dev/null +++ b/Zend/tests/ns_023.phpt @@ -0,0 +1,11 @@ +--TEST-- +023: __NAMESPACE__ constant +--FILE-- +<?php +namespace test::foo; + +var_dump(__NAMESPACE__); +--EXPECT-- +string(9) "test::foo" +--UEXPECT-- +unicode(9) "test::foo" diff --git a/Zend/tests/ns_024.phpt b/Zend/tests/ns_024.phpt new file mode 100755 index 0000000000..6e4f8bb22c --- /dev/null +++ b/Zend/tests/ns_024.phpt @@ -0,0 +1,9 @@ +--TEST-- +024: __NAMESPACE__ constant out of namespace +--FILE-- +<?php +var_dump(__NAMESPACE__); +--EXPECT-- +string(0) "" +--UEXPECT-- +unicode(0) "" diff --git a/Zend/tests/ns_025.phpt b/Zend/tests/ns_025.phpt new file mode 100755 index 0000000000..e5c8ab0044 --- /dev/null +++ b/Zend/tests/ns_025.phpt @@ -0,0 +1,24 @@ +--TEST-- +025: Name ambiguity (class name & part of namespace name) +--FILE-- +<?php +namespace Foo::Bar; + +class Foo { + function __construct() { + echo __CLASS__,"\n"; + } + static function Bar() { + echo __CLASS__,"\n"; + } +} + +$x = new Foo; +Foo::Bar(); +$x = new Foo::Bar::Foo; +Foo::Bar::Foo::Bar(); +--EXPECT-- +Foo::Bar::Foo +Foo::Bar::Foo +Foo::Bar::Foo +Foo::Bar::Foo diff --git a/Zend/tests/ns_026.phpt b/Zend/tests/ns_026.phpt new file mode 100755 index 0000000000..ad8654db5f --- /dev/null +++ b/Zend/tests/ns_026.phpt @@ -0,0 +1,30 @@ +--TEST-- +026: Name ambiguity (class name & namespace name) +--FILE-- +<?php +namespace Foo; + +class Foo { + function __construct() { + echo "Method - ".__CLASS__."::".__FUNCTION__."\n"; + } + static function Bar() { + echo "Method - ".__CLASS__."::".__FUNCTION__."\n"; + } +} + +function Bar() { + echo "Func - ".__FUNCTION__."\n"; +} + +$x = new Foo; +Foo::Bar(); +$x = new Foo::Foo; +Foo::Foo::Bar(); +::Foo::Bar(); +--EXPECT-- +Method - Foo::Foo::__construct +Func - Foo::Bar +Method - Foo::Foo::__construct +Method - Foo::Foo::Bar +Func - Foo::Bar diff --git a/Zend/tests/ns_027.inc b/Zend/tests/ns_027.inc new file mode 100755 index 0000000000..014bc40552 --- /dev/null +++ b/Zend/tests/ns_027.inc @@ -0,0 +1,11 @@ +<?php +namespace Foo::Bar; + +class Foo { + function __construct() { + echo __CLASS__,"\n"; + } + static function Bar() { + echo __CLASS__,"\n"; + } +} diff --git a/Zend/tests/ns_027.phpt b/Zend/tests/ns_027.phpt new file mode 100755 index 0000000000..064d0521f9 --- /dev/null +++ b/Zend/tests/ns_027.phpt @@ -0,0 +1,24 @@ +--TEST-- +027: Name ambiguity (class name & part of extertnal namespace name) +--FILE-- +<?php +require "ns_027.inc"; + +class Foo { + function __construct() { + echo __CLASS__,"\n"; + } + static function Bar() { + echo __CLASS__,"\n"; + } +} + +$x = new Foo; +Foo::Bar(); +$x = new Foo::Bar::Foo; +Foo::Bar::Foo::Bar(); +--EXPECT-- +Foo +Foo +Foo::Bar::Foo +Foo::Bar::Foo diff --git a/Zend/tests/ns_028.inc b/Zend/tests/ns_028.inc new file mode 100755 index 0000000000..5bd3ae7765 --- /dev/null +++ b/Zend/tests/ns_028.inc @@ -0,0 +1,15 @@ +<?php +namespace Foo; + +class Foo { + function __construct() { + echo "Method - ".__CLASS__."::".__FUNCTION__."\n"; + } + static function Bar() { + echo "Method - ".__CLASS__."::".__FUNCTION__."\n"; + } +} + +function Bar() { + echo "Func - ".__FUNCTION__."\n"; +} diff --git a/Zend/tests/ns_028.phpt b/Zend/tests/ns_028.phpt new file mode 100755 index 0000000000..1b34a594b1 --- /dev/null +++ b/Zend/tests/ns_028.phpt @@ -0,0 +1,26 @@ +--TEST-- +028: Name ambiguity (class name & external namespace name) +--FILE-- +<?php +require "ns_028.inc"; + +class Foo { + function __construct() { + echo "Method - ".__CLASS__."::".__FUNCTION__."\n"; + } + static function Bar() { + echo "Method - ".__CLASS__."::".__FUNCTION__."\n"; + } +} + +$x = new Foo; +Foo::Bar(); +$x = new Foo::Foo; +Foo::Foo::Bar(); +::Foo::Bar(); +--EXPECT-- +Method - Foo::__construct +Func - Foo::Bar +Method - Foo::Foo::__construct +Method - Foo::Foo::Bar +Func - Foo::Bar diff --git a/Zend/tests/ns_029.phpt b/Zend/tests/ns_029.phpt new file mode 100755 index 0000000000..a76f4fa9cd --- /dev/null +++ b/Zend/tests/ns_029.phpt @@ -0,0 +1,12 @@ +--TEST-- +029: Name ambiguity (class name & import name) +--FILE-- +<?php +import A::B as Foo; + +class Foo { +} + +new Foo(); +--EXPECTF-- +Fatal error: Class name 'Foo' conflicts with import name in %sns_029.php on line 4 diff --git a/Zend/tests/ns_030.phpt b/Zend/tests/ns_030.phpt new file mode 100755 index 0000000000..c87b293bb6 --- /dev/null +++ b/Zend/tests/ns_030.phpt @@ -0,0 +1,12 @@ +--TEST-- +030: Name ambiguity (import name & class name) +--FILE-- +<?php +class Foo { +} + +import A::B as Foo; + +new Foo(); +--EXPECTF-- +Fatal error: Import name 'Foo' conflicts with defined class in %sns_030.php on line 5 diff --git a/Zend/tests/ns_031.phpt b/Zend/tests/ns_031.phpt new file mode 100755 index 0000000000..3991c5a107 --- /dev/null +++ b/Zend/tests/ns_031.phpt @@ -0,0 +1,21 @@ +--TEST-- +031: Namespace support for user functions (ns name) +--FILE-- +<?php +namespace test; + +class Test { + static function foo() { + echo __CLASS__,"::",__FUNCTION__,"\n"; + } +} + +function foo() { + echo __FUNCTION__,"\n"; +} + +call_user_func(__NAMESPACE__."::foo"); +call_user_func(__NAMESPACE__."::test::foo"); +--EXPECT-- +test::foo +test::Test::foo diff --git a/Zend/tests/ns_032.phpt b/Zend/tests/ns_032.phpt new file mode 100755 index 0000000000..86b24fcdc4 --- /dev/null +++ b/Zend/tests/ns_032.phpt @@ -0,0 +1,19 @@ +--TEST-- +032: Namespace support for user functions (php name) +--FILE-- +<?php +class Test { + static function foo() { + echo __CLASS__,"::",__FUNCTION__,"\n"; + } +} + +function foo() { + echo __FUNCTION__,"\n"; +} + +call_user_func(__NAMESPACE__."::foo"); +call_user_func(__NAMESPACE__."::test::foo"); +--EXPECT-- +foo +Test::foo diff --git a/Zend/tests/ns_033.phpt b/Zend/tests/ns_033.phpt new file mode 100755 index 0000000000..bd0bebd4bd --- /dev/null +++ b/Zend/tests/ns_033.phpt @@ -0,0 +1,8 @@ +--TEST-- +033: Import statement with non-compound name +--FILE-- +<?php +import A; +--EXPECTF-- +Warning: The import statement with non-compound name 'A' has no effect in %sns_033.php on line 2 + diff --git a/Zend/tests/ns_034.phpt b/Zend/tests/ns_034.phpt new file mode 100755 index 0000000000..a0424a9997 --- /dev/null +++ b/Zend/tests/ns_034.phpt @@ -0,0 +1,38 @@ +--TEST-- +034: Support for namespaces in compile-time constant reference +--FILE-- +<?php +namespace A; +import A as B; +class Foo { + const C = "ok\n"; +} +function f1($x=Foo::C) { + echo $x; +} +function f2($x=A::Foo::C) { + echo $x; +} +function f3($x=B::Foo::C) { + echo $x; +} +function f4($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 +ok +ok +ok +ok +ok +ok diff --git a/Zend/tests/ns_035.phpt b/Zend/tests/ns_035.phpt new file mode 100755 index 0000000000..259d17f6e3 --- /dev/null +++ b/Zend/tests/ns_035.phpt @@ -0,0 +1,24 @@ +--TEST-- +035: Name ambiguity in compile-time constant reference (php name) +--SKIPIF-- +<?php if (!extension_loaded("spl")) die("skip SPL is no available"); ?> +--FILE-- +<?php +namespace A; +function f1($x = ArrayObject::STD_PROP_LIST) { + var_dump($x); +} +function f2($x = ::ArrayObject::STD_PROP_LIST) { + var_dump($x); +} +var_dump(ArrayObject::STD_PROP_LIST); +var_dump(::ArrayObject::STD_PROP_LIST); +f1(); +f2(); + +?> +--EXPECT-- +int(1) +int(1) +int(1) +int(1) diff --git a/Zend/tests/ns_036.phpt b/Zend/tests/ns_036.phpt new file mode 100755 index 0000000000..9825c8fc1f --- /dev/null +++ b/Zend/tests/ns_036.phpt @@ -0,0 +1,48 @@ +--TEST-- +036: Name ambiguity in compile-time constant reference (ns name) +--SKIPIF-- +<?php if (!extension_loaded("spl")) die("skip SPL is no available"); ?> +--FILE-- +<?php +namespace A; +import A as B; +class ArrayObject { + const STD_PROP_LIST = 2; +} +function f1($x = ArrayObject::STD_PROP_LIST) { + var_dump($x); +} +function f2($x = ::ArrayObject::STD_PROP_LIST) { + var_dump($x); +} +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) +int(1) +int(2) +int(2) +int(2) +int(2) +int(1) +int(2) +int(2) +int(2) diff --git a/Zend/tests/ns_037.phpt b/Zend/tests/ns_037.phpt new file mode 100755 index 0000000000..4e6c248546 --- /dev/null +++ b/Zend/tests/ns_037.phpt @@ -0,0 +1,49 @@ +--TEST-- +037: Name ambiguity (namespace name or namespace's class name) +--FILE-- +<?php +namespace X; +import X as Y; +class X { + const C = "const ok\n"; + static $var = "var ok\n"; + function __construct() { + echo "class ok\n"; + } + static function bar() { + echo "method ok\n"; + } +} +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 diff --git a/Zend/tests/ns_038.phpt b/Zend/tests/ns_038.phpt new file mode 100755 index 0000000000..fcaa3c4454 --- /dev/null +++ b/Zend/tests/ns_038.phpt @@ -0,0 +1,15 @@ +--TEST-- +038: Name ambiguity (namespace name or internal class name) +--FILE-- +<?php +namespace Exception; +function foo() { + echo "ok\n"; +} +Exception::foo(); +Exception::bar(); +--EXPECTF-- +ok + +Fatal error: Call to undefined method Exception::bar() in %sns_038.php on line 7 + 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.h b/Zend/zend.h index 921eaa1ec5..29f3aea103 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -422,7 +422,9 @@ typedef int (*zend_write_func_t)(const char *str, uint str_length); #define IS_CONSTANT_ARRAY 9 /* 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_API.c b/Zend/zend_API.c index 87118406b3..667b88cba3 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2143,19 +2143,40 @@ static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, ze *ce_ptr = NULL; *fptr_ptr = NULL; - if ((colon = strstr(Z_STRVAL_P(callable), "::")) != NULL) { + + if (!ce_org) { + /* Skip leading :: */ + if (Z_STRVAL_P(callable)[0] == ':' && + Z_STRVAL_P(callable)[1] == ':') { + mlen = Z_STRLEN_P(callable) - 2; + lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + 2, mlen); + } else { + mlen = Z_STRLEN_P(callable); + lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), mlen); + } + /* Check if function with given name exists. + This may be a compound name that includes namespace name */ + if (zend_hash_find(EG(function_table), lmname, mlen+1, (void**)&fptr) == SUCCESS) { + *fptr_ptr = fptr; + efree(lmname); + return 1; + } + efree(lmname); + } + + /* Split name into class/namespace and method/function names */ + if ((colon = zend_memrchr(Z_STRVAL_P(callable), ':', Z_STRLEN_P(callable))) != NULL && + colon > Z_STRVAL_P(callable) && + *(colon-1) == ':') { + colon--; clen = colon - Z_STRVAL_P(callable); mlen = Z_STRLEN_P(callable) - clen - 2; - lcname = zend_str_tolower_dup(Z_STRVAL_P(callable), clen); - /* caution: lcname is not '\0' terminated */ - if (clen == sizeof("self") - 1 && memcmp(lcname, "self", sizeof("self") - 1) == 0) { - *ce_ptr = EG(scope); - } else if (clen == sizeof("parent") - 1 && memcmp(lcname, "parent", sizeof("parent") - 1) == 0 && EG(active_op_array)->scope) { - *ce_ptr = EG(scope) ? EG(scope)->parent : NULL; - } else if (zend_lookup_class(Z_STRVAL_P(callable), clen, &pce TSRMLS_CC) == SUCCESS) { - *ce_ptr = *pce; - } - efree(lcname); + lmname = colon + 2; + } + if (colon != NULL) { + /* This is a compound name. + Try to fetch class and then find static method. */ + *ce_ptr = zend_fetch_class(Z_STRVAL_P(callable), clen, ZEND_FETCH_CLASS_AUTO TSRMLS_CC); if (!*ce_ptr) { return 0; } @@ -2164,15 +2185,15 @@ static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, ze return 0; } lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + clen + 2, mlen); - } else { + } else if (ce_org) { + /* Try to fetch find static method of given class. */ mlen = Z_STRLEN_P(callable); - lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), mlen); - if (ce_org) { - ftable = &ce_org->function_table; - *ce_ptr = ce_org; - } else { - ftable = EG(function_table); - } + lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), Z_STRLEN_P(callable)); + ftable = &ce_org->function_table; + *ce_ptr = ce_org; + } else { + /* We already checked for plain function before. */ + return 0; } retval = zend_hash_find(ftable, lmname, mlen+1, (void**)&fptr) == SUCCESS ? 1 : 0; diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 7341e84ab3..d4ead902ba 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -543,7 +543,7 @@ ZEND_FUNCTION(defined) } convert_to_string_ex(var); - if (zend_get_constant(Z_STRVAL_PP(var), Z_STRLEN_PP(var), &c TSRMLS_CC)) { + if (zend_get_constant_ex(Z_STRVAL_PP(var), Z_STRLEN_PP(var), &c, NULL, 0 TSRMLS_CC)) { zval_dtor(&c); RETURN_TRUE; } else { @@ -744,7 +744,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 2cf8264dc2..6924ea3976 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -138,6 +138,8 @@ void zend_init_compiler_data_structures(TSRMLS_D) CG(handle_op_arrays) = 1; CG(in_compilation) = 0; CG(start_lineno) = 0; + CG(current_namespace) = NULL; + CG(current_import) = NULL; init_compiler_declarables(TSRMLS_C); zend_hash_apply(CG(auto_globals), (apply_func_t) zend_auto_global_arm TSRMLS_CC); @@ -384,13 +386,15 @@ void fetch_simple_variable(znode *result, znode *varname, int bp TSRMLS_DC) fetch_simple_variable_ex(result, varname, bp, ZEND_FETCH_W TSRMLS_CC); } -void zend_do_fetch_static_member(znode *result, znode *class_znode TSRMLS_DC) +void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) { + znode class_node; zend_llist *fetch_list_ptr; zend_llist_element *le; zend_op *opline_ptr; zend_op opline; + zend_do_fetch_class(&class_node, class_name TSRMLS_CC); zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); if (result->op_type == IS_CV) { init_op(&opline TSRMLS_CC); @@ -404,7 +408,7 @@ void zend_do_fetch_static_member(znode *result, znode *class_znode TSRMLS_DC) opline.op1.u.constant.value.str.val = estrdup(CG(active_op_array)->vars[result->u.var].name); opline.op1.u.constant.value.str.len = CG(active_op_array)->vars[result->u.var].name_len; SET_UNUSED(opline.op2); - opline.op2 = *class_znode; + opline.op2 = class_node; opline.op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER; *result = opline.result; @@ -424,13 +428,13 @@ void zend_do_fetch_static_member(znode *result, znode *class_znode TSRMLS_DC) opline.op1.u.constant.value.str.val = estrdup(CG(active_op_array)->vars[opline_ptr->op1.u.var].name); opline.op1.u.constant.value.str.len = CG(active_op_array)->vars[opline_ptr->op1.u.var].name_len; SET_UNUSED(opline.op2); - opline.op2 = *class_znode; + opline.op2 = class_node; opline.op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER; opline_ptr->op1 = opline.result; zend_llist_prepend_element(fetch_list_ptr, &opline); } else { - opline_ptr->op2 = *class_znode; + opline_ptr->op2 = class_node; opline_ptr->op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER; } } @@ -1170,6 +1174,19 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n } else { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + if (CG(current_namespace)) { + /* Prefix function name with current namespcae name */ + znode tmp; + + tmp.u.constant = *CG(current_namespace); + zval_copy_ctor(&tmp.u.constant); + zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC); + op_array.function_name = Z_STRVAL(tmp.u.constant); + efree(lcname); + name_len = Z_STRLEN(tmp.u.constant); + lcname = zend_str_tolower_dup(Z_STRVAL(tmp.u.constant), name_len); + } + opline->opcode = ZEND_DECLARE_FUNCTION; opline->op1.op_type = IS_CONST; build_runtime_defined_function_key(&opline->op1.u.constant, lcname, name_len TSRMLS_CC); @@ -1328,14 +1345,31 @@ void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initia } -int zend_do_begin_function_call(znode *function_name TSRMLS_DC) +int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC) { zend_function *function; char *lcname; + int prefix_len = 0; + + if (check_namespace && CG(current_namespace)) { + /* We assume we call function from the current namespace + if it is not prefixed. */ + znode tmp; + + tmp.op_type = IS_CONST; + tmp.u.constant = *CG(current_namespace); + zval_copy_ctor(&tmp.u.constant); + zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC); + *function_name = tmp; + + /* 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)) + 2; + } 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) { - zend_do_begin_dynamic_function_call(function_name TSRMLS_CC); + zend_do_begin_dynamic_function_call(function_name, prefix_len TSRMLS_CC); efree(lcname); return 1; /* Dynamic */ } @@ -1408,7 +1442,7 @@ void zend_do_clone(znode *result, znode *expr TSRMLS_DC) } -void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC) +void zend_do_begin_dynamic_function_call(znode *function_name, int prefix_len TSRMLS_DC) { unsigned char *ptr = NULL; zend_op *opline; @@ -1418,12 +1452,98 @@ void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC) opline->op2 = *function_name; opline->extended_value = 0; - SET_UNUSED(opline->op1); + if (prefix_len) { + /* In run-time PHP will check for function with full name and + internal function with short name */ + opline->op1.op_type = IS_CONST; + ZVAL_LONG(&opline->op1.u.constant, prefix_len); + } else { + SET_UNUSED(opline->op1); + } zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); zend_do_extended_fcall_begin(TSRMLS_C); } +void zend_resolve_class_name(znode *class_name, ulong *fetch_type, int check_ns_name TSRMLS_DC) +{ + char *compound; + char *lcname; + zval **ns; + znode tmp; + int len; + + compound = memchr(Z_STRVAL(class_name->u.constant), ':', Z_STRLEN(class_name->u.constant)); + if (compound) { + /* This is a compound class name that cotains namespace prefix */ + if (Z_TYPE(class_name->u.constant) == IS_STRING && + Z_STRVAL(class_name->u.constant)[0] == ':') { + /* The STRING name has "::" prefix */ + Z_STRLEN(class_name->u.constant) -= 2; + memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+2, Z_STRLEN(class_name->u.constant)+1); + Z_STRVAL(class_name->u.constant) = erealloc( + Z_STRVAL(class_name->u.constant), + Z_STRLEN(class_name->u.constant) + 1); + } else if (CG(current_import)) { + len = compound - Z_STRVAL(class_name->u.constant); + lcname = zend_str_tolower_dup(Z_STRVAL(class_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) { + /* Substitute import name */ + tmp.op_type = IS_CONST; + tmp.u.constant = **ns; + zval_copy_ctor(&tmp.u.constant); + len += 2; + Z_STRLEN(class_name->u.constant) -= len; + 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); + } + } else if (CG(current_import) || CG(current_namespace)) { + /* this is a plain name (without ::) */ + lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant)); + + if (CG(current_import) && + zend_hash_find(CG(current_import), lcname, Z_STRLEN(class_name->u.constant)+1, (void**)&ns) == SUCCESS) { + /* The given name is an import name. Substitute it. */ + zval_dtor(&class_name->u.constant); + 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) { + char *ns_lcname = zend_str_tolower_dup(Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace))); + + if (Z_STRLEN_P(CG(current_namespace)) == Z_STRLEN(class_name->u.constant) && + memcmp(lcname, ns_lcname, Z_STRLEN(class_name->u.constant)) == 0) { + /* The given name is equal to name of current namespace. + PHP will need to perform additional cheks at run-time to + determine if we assume namespace or class name. */ + *fetch_type |= ZEND_FETCH_CLASS_RT_NS_NAME; + } + efree(ns_lcname); + } + + if (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; + } + tmp.op_type = IS_CONST; + tmp.u.constant = *CG(current_namespace); + zval_copy_ctor(&tmp.u.constant); + zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC); + *class_name = tmp; + } + efree(lcname); + } +} void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) { @@ -1449,6 +1569,7 @@ void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) zval_dtor(&class_name->u.constant); break; default: + zend_resolve_class_name(class_name, &opline->extended_value, 0 TSRMLS_CC); opline->op2 = *class_name; break; } @@ -1457,7 +1578,7 @@ void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) } opline->result.u.var = get_temporary_variable(CG(active_op_array)); opline->result.u.EA.type = opline->extended_value; - opline->result.op_type = IS_CONST; /* FIXME: Hack so that INIT_FCALL_BY_NAME still knows this is a class */ + opline->result.op_type = IS_VAR; /* FIXME: Hack so that INIT_FCALL_BY_NAME still knows this is a class */ *result = opline->result; } @@ -1482,26 +1603,71 @@ void zend_do_fetch_class_name(znode *result, znode *class_name_entry, znode *cla void zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC) { + znode class_node; unsigned char *ptr = NULL; - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - - opline->opcode = ZEND_INIT_STATIC_METHOD_CALL; - opline->op1 = *class_name; - opline->op2 = *method_name; + zend_op *opline; + ulong fetch_type = 0; - if (opline->op2.op_type == IS_CONST) { - char *lcname = zend_str_tolower_dup(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)); - if ((sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == Z_STRLEN(opline->op2.u.constant) && + if (method_name->op_type == IS_CONST) { + char *lcname = zend_str_tolower_dup(Z_STRVAL(method_name->u.constant), Z_STRLEN(method_name->u.constant)); + if ((sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == Z_STRLEN(method_name->u.constant) && memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == 0) { - zval_dtor(&opline->op2.u.constant); - SET_UNUSED(opline->op2); + zval_dtor(&method_name->u.constant); + SET_UNUSED(*method_name); efree(lcname); } else { - efree(opline->op2.u.constant.value.str.val); - opline->op2.u.constant.value.str.val = lcname; + efree(Z_STRVAL(method_name->u.constant)); + Z_STRVAL(method_name->u.constant) = lcname; } } + if (class_name->op_type == IS_CONST && + method_name->op_type == IS_CONST && + ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) { + fetch_type = ZEND_FETCH_CLASS_GLOBAL; + zend_resolve_class_name(class_name, &fetch_type, 1 TSRMLS_CC); + class_node = *class_name; + } else { + zend_do_fetch_class(&class_node, class_name TSRMLS_CC); + } + 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; + + if (class_node.op_type == IS_CONST && + method_name->op_type == IS_CONST) { + /* Prebuild ns::func name to speedup run-time check. + The additional names are stored in additional OP_DATA opcode. */ + char *nsname, *fname; + unsigned int nsname_len, 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_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) + 2; + nsname_len -= (nsname - Z_STRVAL(class_node.u.constant)); + } + len = nsname_len + 2 + Z_STRLEN(method_name->u.constant); + fname = emalloc(len + 1); + memcpy(fname, nsname, nsname_len); + fname[nsname_len] = ':'; + fname[nsname_len + 1] = ':'; + memcpy(fname + nsname_len + 2, + Z_STRVAL(method_name->u.constant), + Z_STRLEN(method_name->u.constant)+1); + zend_str_tolower(fname, len); + opline->extended_value = zend_hash_func(fname, len + 1); + ZVAL_STRINGL(&opline->op1.u.constant, fname, len, 0); + } + zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); zend_do_extended_fcall_begin(TSRMLS_C); } @@ -1779,11 +1945,15 @@ void zend_do_try(znode *try_token TSRMLS_DC) } -void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, zend_bool first_catch TSRMLS_DC) +void zend_do_begin_catch(znode *try_token, znode *class_name, znode *catch_var, znode *first_catch TSRMLS_DC) { - long catch_op_number = get_next_op_number(CG(active_op_array)); + long catch_op_number; zend_op *opline; + znode catch_class; + zend_do_fetch_class(&catch_class, class_name TSRMLS_CC); + + catch_op_number = get_next_op_number(CG(active_op_array)); if (catch_op_number > 0) { opline = &CG(active_op_array)->opcodes[catch_op_number-1]; if (opline->opcode == ZEND_FETCH_CLASS) { @@ -1791,9 +1961,13 @@ void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, } } + if (first_catch) { + first_catch->u.opline_num = catch_op_number; + } + opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_CATCH; - opline->op1 = *catch_class; + opline->op1 = catch_class; /* SET_UNUSED(opline->op1); */ /* FIXME: Define IS_CLASS or something like that */ opline->op2 = *catch_var; opline->op1.u.EA.type = 0; /* 1 means it's the last catch in the block */ @@ -2798,6 +2972,24 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", class_name->u.constant.value.str.val); } + /* Class name must not conflict with import names */ + if (CG(current_import) && + zend_hash_exists(CG(current_import), lcname, Z_STRLEN(class_name->u.constant)+1)) { + zend_error(E_COMPILE_ERROR, "Class name '%s' conflicts with import name", Z_STRVAL(class_name->u.constant)); + } + + if (CG(current_namespace)) { + /* Prefix class name with name of current namespace */ + znode tmp; + + tmp.u.constant = *CG(current_namespace); + zval_copy_ctor(&tmp.u.constant); + zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC); + class_name = &tmp; + efree(lcname); + lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant)); + } + new_class_entry = emalloc(sizeof(zend_class_entry)); new_class_entry->type = ZEND_USER_CLASS; new_class_entry->name = class_name->u.constant.value.str.val; @@ -2910,11 +3102,13 @@ void zend_do_end_class_declaration(znode *class_token, znode *parent_token TSRML } -void zend_do_implements_interface(znode *interface_znode TSRMLS_DC) +void zend_do_implements_interface(znode *interface_name TSRMLS_DC) { + znode interface_node; zend_op *opline; - switch (interface_znode->u.EA.type) { + zend_do_fetch_class(&interface_node, interface_name TSRMLS_CC); + switch (interface_node.u.EA.type) { case ZEND_FETCH_CLASS_SELF: zend_error(E_COMPILE_ERROR, "Cannot use 'self' as interface name as it is reserved"); break; @@ -2934,7 +3128,7 @@ void zend_do_implements_interface(znode *interface_znode TSRMLS_DC) opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_ADD_INTERFACE; opline->op1 = CG(implementing_class); - opline->op2 = *interface_znode; + opline->op2 = interface_node; opline->extended_value = CG(active_class_entry)->num_interfaces++; } @@ -3204,7 +3398,7 @@ void zend_do_end_new_object(znode *result, znode *new_token, znode *argument_lis *result = CG(active_op_array)->opcodes[new_token->u.opline_num].result; } -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; @@ -3213,14 +3407,27 @@ static int zend_constant_ct_subst(znode *result, zval *const_name TSRMLS_DC) if (zend_hash_find(EG(zend_constants), lookup_name, Z_STRLEN_P(const_name)+1, (void **) &c)==SUCCESS) { if ((c->flags & CONST_CS) && memcmp(c->name, Z_STRVAL_P(const_name), Z_STRLEN_P(const_name))!=0) { - c = NULL; + efree(lookup_name); + return NULL; } } else { - c = NULL; + efree(lookup_name); + return NULL; } efree(lookup_name); } - 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; @@ -3230,26 +3437,62 @@ static int zend_constant_ct_subst(znode *result, zval *const_name TSRMLS_DC) } return 0; } +/* }}} */ -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) { + if (ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(constant_container->u.constant), Z_STRLEN(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 = get_next_op(CG(active_op_array) TSRMLS_CC); + zend_op *opline; + if (constant_container) { + if (constant_container->op_type == IS_CONST && + ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(constant_container->u.constant), Z_STRLEN(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) { @@ -3259,6 +3502,35 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con } 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. */ + char *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_STRVAL(constant_container->u.constant); + nsname_len = Z_STRLEN(constant_container->u.constant); + if (fetch_type & ZEND_FETCH_CLASS_RT_NS_NAME) { + /* Remove namespace name */ + nsname = (char *)memchr(nsname, ':', nsname_len) + 2; + nsname_len -= (nsname - Z_STRVAL(constant_container->u.constant)); + } + + Z_TYPE(opline->op1.u.constant) = IS_STRING; + Z_STRVAL(opline->op1.u.constant) = emalloc(nsname_len + 2 + Z_STRLEN(constant_name->u.constant) + 1); + zend_str_tolower_copy(Z_STRVAL(opline->op1.u.constant), nsname, nsname_len); + Z_STRVAL(opline->op1.u.constant)[nsname_len] = ':'; + Z_STRVAL(opline->op1.u.constant)[nsname_len+1] = ':'; + memcpy(Z_STRVAL(opline->op1.u.constant)+nsname_len+2, Z_STRVAL(constant_name->u.constant), Z_STRLEN(constant_name->u.constant) + 1); + Z_STRLEN(opline->op1.u.constant) = nsname_len + 2 + Z_STRLEN(constant_name->u.constant); + opline->extended_value = zend_hash_func(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant) + 1); + } } break; } @@ -3346,7 +3618,7 @@ void zend_do_add_static_array_element(znode *result, znode *offset, znode *expr) ALLOC_ZVAL(element); *element = expr->u.constant; if (offset) { - switch (offset->u.constant.type) { + switch (offset->u.constant.type & 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; @@ -4222,10 +4494,10 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify int zend_get_class_fetch_type(const char *class_name, uint class_name_len) { if ((class_name_len == sizeof("self")-1) && - !memcmp(class_name, "self", sizeof("self"))) { + !memcmp(class_name, "self", sizeof("self")-1)) { return ZEND_FETCH_CLASS_SELF; } else if ((class_name_len == sizeof("parent")-1) && - !memcmp(class_name, "parent", sizeof("parent"))) { + !memcmp(class_name, "parent", sizeof("parent")-1)) { return ZEND_FETCH_CLASS_PARENT; } else { return ZEND_FETCH_CLASS_DEFAULT; @@ -4240,6 +4512,159 @@ ZEND_API char* zend_get_compiled_variable_name(zend_op_array *op_array, zend_uin return op_array->vars[var].name; } +void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRMLS_DC) /* {{{ */ +{ + int len; + + if (prefix) { + *result = *prefix; + } else { + result->op_type = IS_CONST; + Z_TYPE(result->u.constant) = IS_STRING; + Z_STRVAL(result->u.constant) = NULL; + Z_STRLEN(result->u.constant) = 0; + } + len = Z_STRLEN(result->u.constant) + 2 + Z_STRLEN(name->u.constant); + Z_STRVAL(result->u.constant) = erealloc(Z_STRVAL(result->u.constant), len + 1); + Z_STRVAL(result->u.constant)[Z_STRLEN(result->u.constant)] = ':'; + Z_STRVAL(result->u.constant)[Z_STRLEN(result->u.constant)+1] = ':'; + memcpy(Z_STRVAL(result->u.constant)+Z_STRLEN(result->u.constant)+2, + Z_STRVAL(name->u.constant), + Z_STRLEN(name->u.constant)+1); + Z_STRLEN(result->u.constant) = len; + zval_dtor(&name->u.constant); +} +/* }}} */ + +void zend_do_namespace(znode *name TSRMLS_DC) /* {{{ */ +{ + char *lcname; + + if (CG(active_op_array)->last > 0) { + /* ignore ZEND_EXT_STMT */ + int num = CG(active_op_array)->last; + while (num > 0 && + CG(active_op_array)->opcodes[num-1].opcode == ZEND_EXT_STMT) { + --num; + } + if (num > 0) { + zend_error(E_COMPILE_ERROR, "Namespace declaration statement has to be the very first statement in the script"); + } + } + if (CG(current_namespace)) { + zend_error(E_COMPILE_ERROR, "Namespace cannot be declared twice"); + } + lcname = zend_str_tolower_dup(Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant)); + if (((Z_STRLEN(name->u.constant) == sizeof("self")-1) && + !memcmp(lcname, "self", sizeof("self")-1)) || + ((Z_STRLEN(name->u.constant) == sizeof("parent")-1) && + !memcmp(lcname, "parent", sizeof("parent")-1))) { + zend_error(E_COMPILE_ERROR, "Cannot use '%s' as namespace name", Z_STRVAL(name->u.constant)); + } + efree(lcname); + + ALLOC_ZVAL(CG(current_namespace)); + *CG(current_namespace) = name->u.constant; +} +/* }}} */ + +void zend_do_import(znode *ns_name, znode *new_name TSRMLS_DC) /* {{{ */ +{ + char *lcname; + zval *name, *ns, tmp; + zend_bool warn = 0; + + if (!CG(current_import)) { + CG(current_import) = emalloc(sizeof(HashTable)); + zend_hash_init(CG(current_import), 0, NULL, ZVAL_PTR_DTOR, 0); + } + + ALLOC_ZVAL(ns); + *ns = ns_name->u.constant; + if (new_name) { + name = &new_name->u.constant; + } else { + char *p; + + /* The form "import A::B" is eqivalent to "import A::B as B". + So we extract the last part of compound name ti use as a new_name */ + name = &tmp; + p = zend_memrchr(Z_STRVAL_P(ns), ':', Z_STRLEN_P(ns)); + if (p) { + ZVAL_STRING(name, p+1, 1); + } else { + *name = *ns; + zval_copy_ctor(name); + warn = 1; + } + } + + lcname = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name)); + + if (((Z_STRLEN_P(name) == sizeof("self")-1) && + !memcmp(lcname, "self", sizeof("self")-1)) || + ((Z_STRLEN_P(name) == sizeof("parent")-1) && + !memcmp(lcname, "parent", sizeof("parent")-1))) { + zend_error(E_COMPILE_ERROR, "Cannot use '%s' as import name", Z_STRVAL_P(name)); + } + + if (zend_hash_exists(CG(class_table), lcname, Z_STRLEN_P(name)+1)) { + zend_error(E_COMPILE_ERROR, "Import name '%s' conflicts with defined class", Z_STRVAL_P(name)); + } + + if (zend_hash_add(CG(current_import), lcname, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) { + zend_error(E_COMPILE_ERROR, "Cannot reuse import name"); + } + if (warn) { + zend_error(E_WARNING, "The import statement with non-compound name '%s' has no effect", Z_STRVAL_P(name)); + } + efree(lcname); + zval_dtor(name); +} +/* }}} */ + +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 '%s'", Z_STRVAL(name->u.constant)); + } + + if (CG(current_namespace)) { + /* Prefix constant name with name of current namespace */ + znode tmp; + + tmp.op_type = IS_CONST; + tmp.u.constant = *CG(current_namespace); + Z_STRVAL(tmp.u.constant) = zend_str_tolower_dup(Z_STRVAL(tmp.u.constant), Z_STRLEN(tmp.u.constant)); + 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)) { + zval_dtor(CG(current_namespace)); + efree(CG(current_namespace)); + CG(current_namespace) = NULL; + } + if (CG(current_import)) { + zend_hash_destroy(CG(current_import)); + efree(CG(current_import)); + CG(current_import) = NULL; + } +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index cdb7a5ff01..b7321a1f52 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -399,10 +399,10 @@ int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier) void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC); void zend_do_end_function_declaration(znode *function_token TSRMLS_DC); void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, znode *class_type, znode *varname, zend_bool pass_by_reference TSRMLS_DC); -int zend_do_begin_function_call(znode *function_name TSRMLS_DC); +int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC); void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC); void zend_do_clone(znode *result, znode *expr TSRMLS_DC); -void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC); +void zend_do_begin_dynamic_function_call(znode *function_name, int prefix_len TSRMLS_DC); void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC); void zend_do_fetch_class_name(znode *result, znode *class_entry, znode *class_name TSRMLS_DC); void zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC); @@ -411,7 +411,7 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC); void zend_do_handle_exception(TSRMLS_D); void zend_do_try(znode *try_token TSRMLS_DC); -void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, zend_bool first_catch TSRMLS_DC); +void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, znode *first_catch TSRMLS_DC); void zend_do_end_catch(znode *try_token TSRMLS_DC); void zend_do_throw(znode *expr TSRMLS_DC); @@ -458,7 +458,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); @@ -504,6 +504,12 @@ 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); +void zend_do_end_compilation(TSRMLS_D); + ZEND_API void function_add_ref(zend_function *function); #define INITIAL_OP_ARRAY_SIZE 64 @@ -591,6 +597,8 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_FETCH_CLASS_GLOBAL 4 #define ZEND_FETCH_CLASS_AUTO 5 #define ZEND_FETCH_CLASS_INTERFACE 6 +#define ZEND_FETCH_CLASS_RT_NS_CHECK 0x20 +#define ZEND_FETCH_CLASS_RT_NS_NAME 0x40 #define ZEND_FETCH_CLASS_NO_AUTOLOAD 0x80 /* variable parsing type (compile-time) */ diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index fba024ac44..13f9ba9848 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -213,21 +213,82 @@ ZEND_API void zend_register_string_constant(char *name, uint name_len, char *str } -ZEND_API int zend_get_constant_ex(char *name, uint name_len, zval *result, zend_class_entry *scope TSRMLS_DC) +ZEND_API int zend_get_constant(char *name, uint name_len, zval *result TSRMLS_DC) { zend_constant *c; int retval = 1; char *lookup_name; + + if (zend_hash_find(EG(zend_constants), name, name_len+1, (void **) &c) == FAILURE) { + lookup_name = zend_str_tolower_dup(name, name_len); + + if (zend_hash_find(EG(zend_constants), lookup_name, name_len+1, (void **) &c)==SUCCESS) { + if ((c->flags & CONST_CS) && memcmp(c->name, name, name_len) != 0) { + retval=0; + } + } else { + static char haltoff[] = "__COMPILER_HALT_OFFSET__"; + + if (!EG(in_execution)) { + retval = 0; + } else if (name_len == sizeof("__COMPILER_HALT_OFFSET__")-1 && + !memcmp(name, "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) { + char *cfilename, *haltname; + int len, clen; + + cfilename = zend_get_executed_filename(TSRMLS_C); + clen = strlen(cfilename); + /* check for __COMPILER_HALT_OFFSET__ */ + zend_mangle_property_name(&haltname, &len, haltoff, + sizeof("__COMPILER_HALT_OFFSET__") - 1, cfilename, clen, 0); + if (zend_hash_find(EG(zend_constants), haltname, len+1, (void **) &c) == SUCCESS) { + retval = 1; + } else { + retval=0; + } + pefree(haltname, 0); + } else { + retval=0; + } + } + efree(lookup_name); + } + + if (retval) { + *result = c->value; + zval_copy_ctor(result); + result->refcount = 1; + result->is_ref = 0; + } + + return retval; +} + +ZEND_API int zend_get_constant_ex(char *name, uint name_len, zval *result, zend_class_entry *scope, ulong flags TSRMLS_DC) +{ + zend_constant *c; + int retval = 1; char *colon; - if ((colon = memchr(name, ':', name_len)) && colon[1] == ':') { - /* class constant */ - zend_class_entry **ce = NULL; - int class_name_len = colon-name; + /* Skip leading :: */ + if (name[0] == ':' && name[1] == ':') { + name += 2; + name_len -= 2; + flags = 0; + } + + + if ((colon = zend_memrchr(name, ':', name_len)) && + colon > name && + *(colon-1) == ':') { + /* compound constant name */ + zend_class_entry *ce = NULL; + int class_name_len = colon - name - 1; int const_name_len = name_len - class_name_len - 2; - char *constant_name = colon+2; + char *constant_name = constant_name = colon + 1; + char *class_name = estrndup(name, class_name_len); + char *lcname = zend_str_tolower_dup(class_name, class_name_len); zval **ret_constant; - char *class_name; if (!scope) { if (EG(in_execution)) { @@ -236,42 +297,81 @@ ZEND_API int zend_get_constant_ex(char *name, uint name_len, zval *result, zend_ scope = CG(active_class_entry); } } - - class_name = estrndup(name, class_name_len); - if (class_name_len == sizeof("self")-1 && strcmp(class_name, "self") == 0) { + if (class_name_len == sizeof("self")-1 && + !memcmp(lcname, "self", sizeof("self")-1)) { if (scope) { - ce = &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 && strcmp(class_name, "parent") == 0) { - if (!scope) { + efree(lcname); + } else if (class_name_len == sizeof("parent")-1 && + !memcmp(lcname, "parent", sizeof("parent")-1)) { + if (!scope) { zend_error(E_ERROR, "Cannot access parent:: when no class scope is active"); - } else if (!scope->parent) { - zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent"); + } else if (!scope->parent) { + zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent"); } else { - ce = &scope->parent; + ce = scope->parent; } + efree(lcname); } else { - if (zend_lookup_class(class_name, class_name_len, &ce TSRMLS_CC) != SUCCESS) { - retval = 0; + /* Check for namespace constant */ + char *nsname; + unsigned int nsname_len; + + /* Concatenate lowercase namespace name and constant name */ + lcname = erealloc(lcname, class_name_len + 2 + const_name_len + 1); + lcname[class_name_len] = ':'; + lcname[class_name_len+1] = ':'; + memcpy(lcname + class_name_len + 2, constant_name, const_name_len + 1); + + nsname = lcname; + nsname_len = class_name_len + 2 + const_name_len; + if (flags & ZEND_FETCH_CLASS_RT_NS_NAME) { + nsname = (char *)memchr(nsname, ':', nsname_len) + 2; + nsname_len -= (nsname - lcname); + } + + if (zend_hash_find(EG(zend_constants), nsname, nsname_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); + result->refcount = 1; + result->is_ref = 0; + return 1; } + efree(lcname); + + /* Check for class */ + 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) { + if (zend_hash_find(&ce->constants_table, constant_name, const_name_len+1, (void **) &ret_constant) != SUCCESS) { retval = 0; } } else { - zend_error(E_ERROR, "Class '%s' not found", 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); + retval = 1; + return zend_get_constant(name, name_len, result TSRMLS_CC); + } + zend_error(E_ERROR, "Class '%s' not found", class_name); + } retval = 0; } efree(class_name); if (retval) { - zval_update_constant_ex(ret_constant, (void*)1, *ce TSRMLS_CC); + zval_update_constant_ex(ret_constant, (void*)1, ce TSRMLS_CC); *result = **ret_constant; zval_copy_ctor(result); } @@ -279,52 +379,7 @@ ZEND_API int zend_get_constant_ex(char *name, uint name_len, zval *result, zend_ return retval; } - if (zend_hash_find(EG(zend_constants), name, name_len+1, (void **) &c) == FAILURE) { - lookup_name = estrndup(name, name_len); - zend_str_tolower(lookup_name, name_len); - - if (zend_hash_find(EG(zend_constants), lookup_name, name_len+1, (void **) &c)==SUCCESS) { - if ((c->flags & CONST_CS) && memcmp(c->name, name, name_len)!=0) { - retval=0; - } - } else { - char haltoff[] = "__COMPILER_HALT_OFFSET__"; - if (!EG(in_execution)) { - retval = 0; - } else if (name_len == sizeof("__COMPILER_HALT_OFFSET__") - 1 && memcmp(haltoff, name, name_len) == 0) { - char *cfilename, *haltname; - int len, clen; - cfilename = zend_get_executed_filename(TSRMLS_C); - clen = strlen(cfilename); - /* check for __COMPILER_HALT_OFFSET__ */ - zend_mangle_property_name(&haltname, &len, haltoff, - sizeof("__COMPILER_HALT_OFFSET__") - 1, cfilename, clen, 0); - if (zend_hash_find(EG(zend_constants), haltname, len+1, (void **) &c) == SUCCESS) { - retval = 1; - } else { - retval=0; - } - pefree(haltname, 0); - } else { - retval = 0; - } - } - efree(lookup_name); - } - - if (retval) { - *result = c->value; - zval_copy_ctor(result); - result->refcount = 1; - result->is_ref = 0; - } - - return retval; -} - -ZEND_API int zend_get_constant(char *name, uint name_len, zval *result TSRMLS_DC) -{ - return zend_get_constant_ex(name, name_len, result, NULL TSRMLS_CC); + return zend_get_constant(name, name_len, result TSRMLS_CC); } ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC) diff --git a/Zend/zend_constants.h b/Zend/zend_constants.h index 8a983a27e5..17ca7c0316 100644 --- a/Zend/zend_constants.h +++ b/Zend/zend_constants.h @@ -56,7 +56,7 @@ 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_get_constant_ex(char *name, uint name_len, zval *result, zend_class_entry *scope TSRMLS_DC); +ZEND_API int zend_get_constant_ex(char *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 211036bbea..c16e65d511 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -461,7 +461,7 @@ ZEND_API int zval_update_constant_ex(zval **pp, void *arg, zend_class_entry *sco if (IS_CONSTANT_VISITED(p)) { zend_error(E_ERROR, "Cannot declare self-referencing constant '%s'", Z_STRVAL_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; @@ -473,7 +473,7 @@ 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_get_constant_ex(p->value.str.val, p->value.str.len, &const_value, scope TSRMLS_CC)) { + if (!zend_get_constant_ex(p->value.str.val, p->value.str.len, &const_value, scope, Z_TYPE_P(p) TSRMLS_CC)) { if ((colon = memchr(Z_STRVAL_P(p), ':', Z_STRLEN_P(p))) && colon[1] == ':') { zend_error(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(p)); } @@ -515,7 +515,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_get_constant_ex(str_index, str_index_len-1, &const_value, scope TSRMLS_CC)) { + if (!zend_get_constant_ex(str_index, str_index_len-1, &const_value, scope, 0 TSRMLS_CC)) { if ((colon = memchr(str_index, ':', str_index_len-1)) && colon[1] == ':') { zend_error(E_ERROR, "Undefined class constant '%s'", str_index); } @@ -636,6 +636,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS int call_via_handler = 0; char *fname, *colon; int fname_len; + char *lcname; *fci->retval_ptr_ptr = NULL; @@ -766,68 +767,76 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS fname = Z_STRVAL_P(fci->function_name); fname_len = Z_STRLEN_P(fci->function_name); - if ((colon = strstr(fname, "::")) != NULL) { - int clen = colon - fname; - int mlen = fname_len - clen - 2; - zend_class_entry **pce, *ce_child = NULL; - if (zend_lookup_class(fname, clen, &pce TSRMLS_CC) == SUCCESS) { - ce_child = *pce; - } else { - char *lcname = zend_str_tolower_dup(fname, clen); - /* caution: lcname is not '\0' terminated */ - if (calling_scope) { - if (clen == sizeof("self") - 1 && memcmp(lcname, "self", sizeof("self") - 1) == 0) { - ce_child = EG(active_op_array) ? EG(active_op_array)->scope : NULL; - } else if (clen == sizeof("parent") - 1 && memcmp(lcname, "parent", sizeof("parent") - 1) == 0 && EG(active_op_array)->scope) { - ce_child = EG(active_op_array) && EG(active_op_array)->scope ? EG(scope)->parent : NULL; + if (fname[0] == ':' && fname[1] == ':') { + fname += 2; + fname_len -=2; + } + lcname = zend_str_tolower_dup(fname, fname_len); + EX(function_state).function = NULL; + if (!fci->object_pp && + zend_hash_find(fci->function_table, lcname, fname_len+1, (void**)&EX(function_state).function) == SUCCESS) { + efree(lcname); + } else { + efree(lcname); + if ((colon = zend_memrchr(fname, ':', fname_len)) != NULL && + colon > fname && + *(colon-1) == ':') { + int clen = colon - fname - 1; + int mlen = fname_len - clen - 2; + + zend_class_entry **pce, *ce_child = NULL; + if (zend_lookup_class(fname, clen, &pce TSRMLS_CC) == SUCCESS) { + ce_child = *pce; + } else { + char *lcname = zend_str_tolower_dup(fname, clen); + /* caution: lcname is not '\0' terminated */ + if (calling_scope) { + if (clen == sizeof("self") - 1 && memcmp(lcname, "self", sizeof("self") - 1) == 0) { + ce_child = EG(active_op_array) ? EG(active_op_array)->scope : NULL; + } else if (clen == sizeof("parent") - 1 && memcmp(lcname, "parent", sizeof("parent") - 1) == 0 && EG(active_op_array)->scope) { + ce_child = EG(active_op_array) && EG(active_op_array)->scope ? EG(scope)->parent : NULL; + } } + efree(lcname); } - efree(lcname); - } - if (!ce_child) { - zend_error(E_ERROR, "Cannot call method %s() or method does not exist", fname); - return FAILURE; + if (!ce_child) { + zend_error(E_ERROR, "Cannot call method %s() or method does not exist", fname); + return FAILURE; + } + check_scope_or_static = calling_scope; + fci->function_table = &ce_child->function_table; + calling_scope = ce_child; + fname = fname + clen + 2; + fname_len = mlen; } - check_scope_or_static = calling_scope; - fci->function_table = &ce_child->function_table; - calling_scope = ce_child; - fname = fname + clen + 2; - fname_len = mlen; - } - if (fci->object_pp) { - if (Z_OBJ_HT_PP(fci->object_pp)->get_method == NULL) { - zend_error(E_ERROR, "Object does not support method calls"); - } - EX(function_state).function = - Z_OBJ_HT_PP(fci->object_pp)->get_method(fci->object_pp, fname, fname_len TSRMLS_CC); - if (EX(function_state).function && calling_scope != EX(function_state).function->common.scope) { - char *function_name_lc = zend_str_tolower_dup(fname, fname_len); - if (zend_hash_find(&calling_scope->function_table, function_name_lc, fname_len+1, (void **) &EX(function_state).function)==FAILURE) { + if (fci->object_pp) { + if (Z_OBJ_HT_PP(fci->object_pp)->get_method == NULL) { + zend_error(E_ERROR, "Object does not support method calls"); + } + EX(function_state).function = + Z_OBJ_HT_PP(fci->object_pp)->get_method(fci->object_pp, fname, fname_len TSRMLS_CC); + if (EX(function_state).function && calling_scope != EX(function_state).function->common.scope) { + char *function_name_lc = zend_str_tolower_dup(fname, fname_len); + if (zend_hash_find(&calling_scope->function_table, function_name_lc, fname_len+1, (void **) &EX(function_state).function)==FAILURE) { + efree(function_name_lc); + zend_error(E_ERROR, "Cannot call method %s::%s() or method does not exist", calling_scope->name, fname); + } efree(function_name_lc); - zend_error(E_ERROR, "Cannot call method %s::%s() or method does not exist", calling_scope->name, fname); } - efree(function_name_lc); - } - } else if (calling_scope) { - char *function_name_lc = zend_str_tolower_dup(fname, fname_len); - - EX(function_state).function = - zend_std_get_static_method(calling_scope, function_name_lc, fname_len TSRMLS_CC); - efree(function_name_lc); - if (check_scope_or_static && EX(function_state).function - && !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC) - && !instanceof_function(check_scope_or_static, calling_scope TSRMLS_CC)) { - zend_error(E_ERROR, "Cannot call method %s() of class %s which is not a derived from %s", fname, calling_scope->name, check_scope_or_static->name); - return FAILURE; - } - } else { - char *function_name_lc = zend_str_tolower_dup(fname, fname_len); + } else if (calling_scope) { + char *function_name_lc = zend_str_tolower_dup(fname, fname_len); - if (zend_hash_find(fci->function_table, function_name_lc, fname_len+1, (void **) &EX(function_state).function)==FAILURE) { - EX(function_state).function = NULL; + EX(function_state).function = + zend_std_get_static_method(calling_scope, function_name_lc, fname_len TSRMLS_CC); + efree(function_name_lc); + if (check_scope_or_static && EX(function_state).function + && !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC) + && !instanceof_function(check_scope_or_static, calling_scope TSRMLS_CC)) { + zend_error(E_ERROR, "Cannot call method %s() of class %s which is not a derived from %s", fname, calling_scope->name, check_scope_or_static->name); + return FAILURE; + } } - efree(function_name_lc); } if (EX(function_state).function == NULL) { @@ -1033,6 +1042,7 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_aut zval *retval_ptr = NULL; int retval; char *lc_name; + char *lc_free; zval *exception; char dummy = 1; zend_fcall_info fcall_info; @@ -1042,11 +1052,16 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_aut return FAILURE; } - lc_name = do_alloca(name_length + 1); + lc_free = lc_name = do_alloca(name_length + 1); zend_str_tolower_copy(lc_name, name, name_length); + if (lc_name[0] == ':' && lc_name[1] == ':') { + lc_name += 2; + name_length -= 2; + } + if (zend_hash_find(EG(class_table), lc_name, name_length+1, (void **) ce) == SUCCESS) { - free_alloca(lc_name); + free_alloca(lc_free); return SUCCESS; } @@ -1054,7 +1069,7 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_aut * (doesn't impact fuctionality of __autoload() */ if (!use_autoload || zend_is_compiling(TSRMLS_C)) { - free_alloca(lc_name); + free_alloca(lc_free); return FAILURE; } @@ -1064,7 +1079,7 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_aut } if (zend_hash_add(EG(in_autoload), lc_name, name_length+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) { - free_alloca(lc_name); + free_alloca(lc_free); return FAILURE; } @@ -1102,12 +1117,12 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_aut if (retval == FAILURE) { EG(exception) = exception; - free_alloca(lc_name); + free_alloca(lc_free); return FAILURE; } if (EG(exception) && exception) { - free_alloca(lc_name); + free_alloca(lc_free); zend_error(E_ERROR, "Function %s(%s) threw an exception of type '%s'", ZEND_AUTOLOAD_FUNC_NAME, name, Z_OBJCE_P(EG(exception))->name); return FAILURE; } @@ -1119,7 +1134,7 @@ ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_aut } retval = zend_hash_find(EG(class_table), lc_name, name_length + 1, (void **) ce); - free_alloca(lc_name); + free_alloca(lc_free); return retval; } @@ -1475,6 +1490,7 @@ 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; fetch_type = fetch_type & ~ZEND_FETCH_CLASS_NO_AUTOLOAD; check_fetch_type: @@ -1501,8 +1517,30 @@ check_fetch_type: break; } - if (zend_lookup_class_ex(class_name, class_name_len, use_autoload, &pce TSRMLS_CC)==FAILURE) { + 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 (use_autoload) { + if (rt_ns_check && + zend_lookup_class_ex(class_name, class_name_len, 1, &pce TSRMLS_CC)==SUCCESS) { + return *pce; + } if (fetch_type == ZEND_FETCH_CLASS_INTERFACE) { zend_error(E_ERROR, "Interface '%s' not found", class_name); } else { diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 9351239499..832053730c 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -130,6 +130,9 @@ struct _zend_compiler_globals { char *doc_comment; zend_uint doc_comment_len; + zval *current_namespace; + HashTable *current_import; + #ifdef ZEND_MULTIBYTE zend_encoding **script_encoding_list; int script_encoding_list_size; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 244daae9e5..3edbbb2c0b 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -143,11 +143,14 @@ %token T_DOLLAR_OPEN_CURLY_BRACES %token T_CURLY_OPEN %token T_PAAMAYIM_NEKUDOTAYIM +%token T_NAMESPACE +%token T_IMPORT +%token T_NS_C %% /* Rules */ start: - top_statement_list + top_statement_list { zend_do_end_compilation(TSRMLS_C); } ; top_statement_list: @@ -155,14 +158,26 @@ top_statement_list: | /* empty */ ; +namespace_name: + T_STRING { $$ = $1; } + | namespace_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, &$1, &$3 TSRMLS_CC); } +; top_statement: statement | function_declaration_statement { zend_do_early_binding(TSRMLS_C); } | class_declaration_statement { zend_do_early_binding(TSRMLS_C); } - | T_HALT_COMPILER '(' ')' ';' { zend_do_halt_compiler_register(TSRMLS_C); YYACCEPT; } + | T_HALT_COMPILER '(' ')' ';' { zend_do_halt_compiler_register(TSRMLS_C); YYACCEPT; } + | 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(); } @@ -225,7 +240,7 @@ unticked_statement: | T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}' T_CATCH '(' { zend_initialize_try_catch_element(&$1 TSRMLS_CC); } fully_qualified_class_name { zend_do_first_catch(&$7 TSRMLS_CC); } - T_VARIABLE ')' { zend_do_begin_catch(&$1, &$9, &$11, 1 TSRMLS_CC); } + T_VARIABLE ')' { zend_do_begin_catch(&$1, &$9, &$11, &$7 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } additional_catches { zend_do_mark_last_catch(&$7, &$18 TSRMLS_CC); } | T_THROW expr ';' { zend_do_throw(&$2 TSRMLS_CC); } @@ -244,7 +259,7 @@ non_empty_additional_catches: additional_catch: - T_CATCH '(' fully_qualified_class_name { $$.u.opline_num = get_next_op_number(CG(active_op_array)); } T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$5, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } + T_CATCH '(' fully_qualified_class_name { $$.u.opline_num = get_next_op_number(CG(active_op_array)); } T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$5, NULL TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } ; @@ -307,7 +322,7 @@ class_entry_type: extends_from: /* empty */ { $$.op_type = IS_UNUSED; } - | T_EXTENDS fully_qualified_class_name { $$ = $2; } + | T_EXTENDS fully_qualified_class_name { zend_do_fetch_class(&$$, &$2 TSRMLS_CC); } ; interface_entry: @@ -621,9 +636,12 @@ expr_without_variable: ; function_call: - T_STRING '(' { $2.u.opline_num = zend_do_begin_function_call(&$1 TSRMLS_CC); } + T_STRING '(' { $2.u.opline_num = zend_do_begin_function_call(&$1, 1 TSRMLS_CC); } function_call_parameter_list ')' { zend_do_end_function_call(&$1, &$$, &$4, 0, $2.u.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } + | T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { $3.u.opline_num = zend_do_begin_function_call(&$2, 0 TSRMLS_CC); } + function_call_parameter_list + ')' { zend_do_end_function_call(&$2, &$$, &$5, 0, $3.u.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} @@ -636,17 +654,19 @@ function_call: | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects '(' { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} - | variable_without_objects '(' { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_dynamic_function_call(&$1 TSRMLS_CC); } + | variable_without_objects '(' { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); } function_call_parameter_list ')' { zend_do_end_function_call(&$1, &$$, &$4, 0, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} ; fully_qualified_class_name: - T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + T_STRING { $$ = $1; } + | T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, NULL, &$2 TSRMLS_CC); } + | fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, &$1, &$3 TSRMLS_CC); } ; class_name_reference: - T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + fully_qualified_class_name { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } | dynamic_class_name_reference { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } ; @@ -691,12 +711,14 @@ common_scalar: | T_CLASS_C { $$ = $1; } | T_METHOD_C { $$ = $1; } | T_FUNC_C { $$ = $1; } + | T_NS_C { $$ = $1; } ; 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; } @@ -704,11 +726,12 @@ static_scalar: /* compile-time evaluated scalars */ ; static_class_constant: - T_STRING 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; } @@ -792,7 +815,7 @@ static_member: ; variable_class_name: - reference_variable { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + reference_variable { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); $$=$1;; } ; base_variable_with_function_calls: @@ -917,8 +940,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_language_scanner.l b/Zend/zend_language_scanner.l index 436e6e5566..f05ab62394 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -1198,6 +1198,14 @@ HEREDOC_CHARS ("{"*([^$\n\r\\{]|("\\"[^\n\r]))|{HEREDOC_LITERAL_DOLLAR}|({ return T_REQUIRE_ONCE; } +<ST_IN_SCRIPTING>"namespace" { + return T_NAMESPACE; +} + +<ST_IN_SCRIPTING>"import" { + return T_IMPORT; +} + <ST_IN_SCRIPTING>"use" { return T_USE; } @@ -1543,6 +1551,16 @@ HEREDOC_CHARS ("{"*([^$\n\r\\{]|("\\"[^\n\r]))|{HEREDOC_LITERAL_DOLLAR}|({ return T_FILE; } +<ST_IN_SCRIPTING>"__NAMESPACE__" { + if (CG(current_namespace)) { + *zendlval = *CG(current_namespace); + zval_copy_ctor(zendlval); + } else { + ZVAL_EMPTY_STRING(zendlval); + } + return T_NS_C; +} + <INITIAL>(([^<]|"<"[^?%s<]){1,400})|"<s"|"<" { #ifdef ZEND_MULTIBYTE if (SCNG(output_filter)) { diff --git a/Zend/zend_variables.c b/Zend/zend_variables.c index 7df3a7ecaa..fecaf7811c 100644 --- a/Zend/zend_variables.c +++ b/Zend/zend_variables.c @@ -29,7 +29,7 @@ ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC) { - switch (zvalue->type & ~IS_CONSTANT_INDEX) { + switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) { case IS_STRING: case IS_CONSTANT: CHECK_ZVAL_STRING_REL(zvalue); @@ -73,7 +73,7 @@ ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC) ZEND_API void _zval_internal_dtor(zval *zvalue ZEND_FILE_LINE_DC) { - switch (zvalue->type & ~IS_CONSTANT_INDEX) { + switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) { case IS_STRING: case IS_CONSTANT: CHECK_ZVAL_STRING_REL(zvalue); @@ -103,7 +103,7 @@ ZEND_API void zval_add_ref(zval **p) ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC) { - switch (zvalue->type) { + 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 7662d85074..1ceae37139 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1730,7 +1730,7 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, ANY, CONST|TMP|VAR|UNUSED|CV) +ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUSED|CV) { zend_op *opline = EX(opline); zval *function_name; @@ -1738,7 +1738,25 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, ANY, CONST|TMP|VAR|UNUSED|CV) zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); - ce = EX_T(opline->op1.u.var).class_entry; + if (OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) { + /* try a function in namespace */ + zend_op *op_data = opline+1; + + ZEND_VM_INC_OPCODE(); + + 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))==SUCCESS) { + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + + /* no function found. try a static method in class */ + ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL(opline->op1.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } if(OP2_TYPE != IS_UNUSED) { char *function_name_strval; int function_name_strlen; @@ -1818,10 +1836,29 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) function_name_strlen = function_name->value.str.len; } - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); + if (OP2_TYPE != IS_CONST && + function_name_strval[0] == ':' && + function_name_strval[1] == ':') { + + function_name_strlen -= 2; + lcname = zend_str_tolower_dup(function_name_strval + 2, function_name_strlen); + } else { + lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); + } if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + + if (OP2_TYPE == IS_CONST && opline->op1.op_type == IS_CONST) { + function_name_strlen -= Z_LVAL(opline->op1.u.constant); + lcname = zend_str_tolower_dup(function_name_strval + Z_LVAL(opline->op1.u.constant), function_name_strlen); + if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE || + function->type != ZEND_INTERNAL_FUNCTION) { + efree(lcname); + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + } + } else { + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + } } efree(lcname); @@ -2366,7 +2403,7 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST) zend_free_op free_res; if (zend_ptr_stack_get_arg(arg_num, (void **) ¶m 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); @@ -2582,49 +2619,71 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMP|VAR|UNUSED|CV, ANY) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, CONST|UNUSED, CONST) +ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, 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_get_constant(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len, &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { + if (!zend_get_constant(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", - opline->op2.u.constant.value.str.val, - opline->op2.u.constant.value.str.val); + Z_STRVAL(opline->op2.u.constant), + Z_STRVAL(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 { + zend_class_entry *ce; + zval **value; + + if (OP1_TYPE == IS_CONST) { + zend_op *op_data = opline + 1; + zend_constant *c; + + ZEND_VM_INC_OPCODE(); + + /* try a constant in namespace */ + if (zend_hash_quick_find(EG(zend_constants), Z_STRVAL(op_data->op1.u.constant), Z_STRLEN(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_get_constant(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { + 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; + 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_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL(opline->op2.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } - ce = EX_T(opline->op1.u.var).class_entry; + if (zend_hash_find(&ce->constants_table, Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { + if (Z_TYPE_PP(value) == IS_CONSTANT_ARRAY || + Z_TYPE_PP(value) == IS_CONSTANT) { + zend_class_entry *old_scope = EG(scope); - if (zend_hash_find(&ce->constants_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+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 '%s'", Z_STRVAL(opline->op2.u.constant)); + } - 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 '%s'", opline->op2.u.constant.value.str.val); + ZEND_VM_NEXT_OPCODE(); } - - ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(72, ZEND_ADD_ARRAY_ELEMENT, CONST|TMP|VAR|CV, CONST|TMP|VAR|UNUSED|CV) @@ -3846,4 +3905,39 @@ ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, ANY, ANY) } } +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 */ + c.name = zend_strndup(Z_STRVAL_P(name), Z_STRLEN_P(name)); + c.name_len = Z_STRLEN_P(name)+1; + c.module_number = PHP_USER_CONSTANT; + + if (zend_register_constant(&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 2eb63d2e31..2df3ee8e31 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -656,70 +656,6 @@ static int ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } -static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - zend_op *opline = EX(opline); - zval *function_name; - zend_class_entry *ce; - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); - - ce = EX_T(opline->op1.u.var).class_entry; - if(IS_CONST != IS_UNUSED) { - char *function_name_strval; - int function_name_strlen; - zend_bool is_const = (IS_CONST == IS_CONST); - - - if (is_const) { - function_name_strval = Z_STRVAL(opline->op2.u.constant); - function_name_strlen = Z_STRLEN(opline->op2.u.constant); - } else { - function_name = &opline->op2.u.constant; - - if (Z_TYPE_P(function_name) != IS_STRING) { - zend_error_noreturn(E_ERROR, "Function name must be a string"); - } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; - } - - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); - - if (!is_const) { - efree(function_name_strval); - - } - } else { - if(!ce->constructor) { - zend_error_noreturn(E_ERROR, "Can not call constructor"); - } - if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); - } - EX(fbc) = ce->constructor; - } - - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; - } else { - if (IS_CONST != IS_UNUSED && - EG(This) && - Z_OBJ_HT_P(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); - - } - if ((EX(object) = EG(This))) { - EX(object)->refcount++; - } - } - - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -744,10 +680,29 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) function_name_strlen = function_name->value.str.len; } - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); + if (IS_CONST != IS_CONST && + function_name_strval[0] == ':' && + function_name_strval[1] == ':') { + + function_name_strlen -= 2; + lcname = zend_str_tolower_dup(function_name_strval + 2, function_name_strlen); + } else { + lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); + } if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + + if (IS_CONST == IS_CONST && opline->op1.op_type == IS_CONST) { + function_name_strlen -= Z_LVAL(opline->op1.u.constant); + lcname = zend_str_tolower_dup(function_name_strval + Z_LVAL(opline->op1.u.constant), function_name_strlen); + if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE || + function->type != ZEND_INTERNAL_FUNCTION) { + efree(lcname); + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + } + } else { + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + } } efree(lcname); @@ -771,7 +726,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 **) ¶m 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); @@ -860,70 +815,6 @@ static int ZEND_FETCH_CLASS_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } -static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - zend_op *opline = EX(opline); - zval *function_name; - zend_class_entry *ce; - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); - - ce = EX_T(opline->op1.u.var).class_entry; - if(IS_TMP_VAR != IS_UNUSED) { - char *function_name_strval; - int function_name_strlen; - zend_bool is_const = (IS_TMP_VAR == IS_CONST); - zend_free_op free_op2; - - if (is_const) { - function_name_strval = Z_STRVAL(opline->op2.u.constant); - function_name_strlen = Z_STRLEN(opline->op2.u.constant); - } else { - function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - - if (Z_TYPE_P(function_name) != IS_STRING) { - zend_error_noreturn(E_ERROR, "Function name must be a string"); - } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; - } - - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); - - if (!is_const) { - efree(function_name_strval); - zval_dtor(free_op2.var); - } - } else { - if(!ce->constructor) { - zend_error_noreturn(E_ERROR, "Can not call constructor"); - } - if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); - } - EX(fbc) = ce->constructor; - } - - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; - } else { - if (IS_TMP_VAR != IS_UNUSED && - EG(This) && - Z_OBJ_HT_P(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); - - } - if ((EX(object) = EG(This))) { - EX(object)->refcount++; - } - } - - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -948,10 +839,29 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) function_name_strlen = function_name->value.str.len; } - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); + if (IS_TMP_VAR != IS_CONST && + function_name_strval[0] == ':' && + function_name_strval[1] == ':') { + + function_name_strlen -= 2; + lcname = zend_str_tolower_dup(function_name_strval + 2, function_name_strlen); + } else { + lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); + } if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + + if (IS_TMP_VAR == IS_CONST && opline->op1.op_type == IS_CONST) { + function_name_strlen -= Z_LVAL(opline->op1.u.constant); + lcname = zend_str_tolower_dup(function_name_strval + Z_LVAL(opline->op1.u.constant), function_name_strlen); + if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE || + function->type != ZEND_INTERNAL_FUNCTION) { + efree(lcname); + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + } + } else { + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + } } efree(lcname); @@ -1021,70 +931,6 @@ static int ZEND_FETCH_CLASS_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } -static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - zend_op *opline = EX(opline); - zval *function_name; - zend_class_entry *ce; - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); - - ce = EX_T(opline->op1.u.var).class_entry; - if(IS_VAR != IS_UNUSED) { - char *function_name_strval; - int function_name_strlen; - zend_bool is_const = (IS_VAR == IS_CONST); - zend_free_op free_op2; - - if (is_const) { - function_name_strval = Z_STRVAL(opline->op2.u.constant); - function_name_strlen = Z_STRLEN(opline->op2.u.constant); - } else { - function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); - - if (Z_TYPE_P(function_name) != IS_STRING) { - zend_error_noreturn(E_ERROR, "Function name must be a string"); - } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; - } - - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); - - if (!is_const) { - efree(function_name_strval); - if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; - } - } else { - if(!ce->constructor) { - zend_error_noreturn(E_ERROR, "Can not call constructor"); - } - if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); - } - EX(fbc) = ce->constructor; - } - - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; - } else { - if (IS_VAR != IS_UNUSED && - EG(This) && - Z_OBJ_HT_P(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); - - } - if ((EX(object) = EG(This))) { - EX(object)->refcount++; - } - } - - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -1109,10 +955,29 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) function_name_strlen = function_name->value.str.len; } - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); + if (IS_VAR != IS_CONST && + function_name_strval[0] == ':' && + function_name_strval[1] == ':') { + + function_name_strlen -= 2; + lcname = zend_str_tolower_dup(function_name_strval + 2, function_name_strlen); + } else { + lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); + } if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + + if (IS_VAR == IS_CONST && opline->op1.op_type == IS_CONST) { + function_name_strlen -= Z_LVAL(opline->op1.u.constant); + lcname = zend_str_tolower_dup(function_name_strval + Z_LVAL(opline->op1.u.constant), function_name_strlen); + if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE || + function->type != ZEND_INTERNAL_FUNCTION) { + efree(lcname); + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + } + } else { + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + } } efree(lcname); @@ -1181,70 +1046,6 @@ static int ZEND_FETCH_CLASS_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } -static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - zend_op *opline = EX(opline); - zval *function_name; - zend_class_entry *ce; - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); - - ce = EX_T(opline->op1.u.var).class_entry; - if(IS_UNUSED != IS_UNUSED) { - char *function_name_strval; - int function_name_strlen; - zend_bool is_const = (IS_UNUSED == IS_CONST); - - - if (is_const) { - function_name_strval = Z_STRVAL(opline->op2.u.constant); - function_name_strlen = Z_STRLEN(opline->op2.u.constant); - } else { - function_name = NULL; - - if (Z_TYPE_P(function_name) != IS_STRING) { - zend_error_noreturn(E_ERROR, "Function name must be a string"); - } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; - } - - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); - - if (!is_const) { - efree(function_name_strval); - - } - } else { - if(!ce->constructor) { - zend_error_noreturn(E_ERROR, "Can not call constructor"); - } - if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); - } - EX(fbc) = ce->constructor; - } - - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; - } else { - if (IS_UNUSED != IS_UNUSED && - EG(This) && - Z_OBJ_HT_P(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); - - } - if ((EX(object) = EG(This))) { - EX(object)->refcount++; - } - } - - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_FETCH_CLASS_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -1274,70 +1075,6 @@ static int ZEND_FETCH_CLASS_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } -static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - zend_op *opline = EX(opline); - zval *function_name; - zend_class_entry *ce; - - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); - - ce = EX_T(opline->op1.u.var).class_entry; - if(IS_CV != IS_UNUSED) { - char *function_name_strval; - int function_name_strlen; - zend_bool is_const = (IS_CV == IS_CONST); - - - if (is_const) { - function_name_strval = Z_STRVAL(opline->op2.u.constant); - function_name_strlen = Z_STRLEN(opline->op2.u.constant); - } else { - function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); - - if (Z_TYPE_P(function_name) != IS_STRING) { - zend_error_noreturn(E_ERROR, "Function name must be a string"); - } - function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); - function_name_strlen = function_name->value.str.len; - } - - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); - - if (!is_const) { - efree(function_name_strval); - - } - } else { - if(!ce->constructor) { - zend_error_noreturn(E_ERROR, "Can not call constructor"); - } - if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); - } - EX(fbc) = ce->constructor; - } - - if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { - EX(object) = NULL; - } else { - if (IS_CV != IS_UNUSED && - EG(This) && - Z_OBJ_HT_P(EG(This))->get_class_entry && - !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { - /* We are calling method of the other (incompatible) class, - but passing $this. This is done for compatibility with php-4. */ - zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); - - } - if ((EX(object) = EG(This))) { - EX(object)->refcount++; - } - } - - ZEND_VM_NEXT_OPCODE(); -} - static int ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -1362,10 +1099,29 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) function_name_strlen = function_name->value.str.len; } - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); + if (IS_CV != IS_CONST && + function_name_strval[0] == ':' && + function_name_strval[1] == ':') { + + function_name_strlen -= 2; + lcname = zend_str_tolower_dup(function_name_strval + 2, function_name_strlen); + } else { + lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); + } if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE) { efree(lcname); - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + + if (IS_CV == IS_CONST && opline->op1.op_type == IS_CONST) { + function_name_strlen -= Z_LVAL(opline->op1.u.constant); + lcname = zend_str_tolower_dup(function_name_strval + Z_LVAL(opline->op1.u.constant), function_name_strlen); + if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &function)==FAILURE || + function->type != ZEND_INTERNAL_FUNCTION) { + efree(lcname); + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + } + } else { + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + } } efree(lcname); @@ -2630,6 +2386,88 @@ static int ZEND_FETCH_DIM_TMP_VAR_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_A ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_CONST == IS_CONST && IS_CONST == IS_CONST) { + /* try a function in namespace */ + zend_op *op_data = opline+1; + + ZEND_VM_INC_OPCODE(); + + 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))==SUCCESS) { + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + + /* no function found. try a static method in class */ + ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL(opline->op1.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_CONST != IS_UNUSED) { + char *function_name_strval; + int function_name_strlen; + zend_bool is_const = (IS_CONST == IS_CONST); + + + if (is_const) { + function_name_strval = Z_STRVAL(opline->op2.u.constant); + function_name_strlen = Z_STRLEN(opline->op2.u.constant); + } else { + function_name = &opline->op2.u.constant; + + if (Z_TYPE_P(function_name) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); + function_name_strlen = function_name->value.str.len; + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval); + + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_CONST != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -2664,46 +2502,68 @@ static int ZEND_CASE_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) 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) { -/* 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_get_constant(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len, &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { + if (!zend_get_constant(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", - opline->op2.u.constant.value.str.val, - opline->op2.u.constant.value.str.val); + Z_STRVAL(opline->op2.u.constant), + Z_STRVAL(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 { + zend_class_entry *ce; + zval **value; - ce = EX_T(opline->op1.u.var).class_entry; + if (IS_CONST == IS_CONST) { + zend_op *op_data = opline + 1; + zend_constant *c; - if (zend_hash_find(&ce->constants_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, (void **) &value) == SUCCESS) { - zend_class_entry *old_scope = EG(scope); + ZEND_VM_INC_OPCODE(); - 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 '%s'", opline->op2.u.constant.value.str.val); - } + /* try a constant in namespace */ + if (zend_hash_quick_find(EG(zend_constants), Z_STRVAL(op_data->op1.u.constant), Z_STRLEN(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_get_constant(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { + 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; + zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); + } + ZEND_VM_NEXT_OPCODE(); + } - ZEND_VM_NEXT_OPCODE(); + /* no constant found. try a constant in class */ + ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL(opline->op2.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + + if (zend_hash_find(&ce->constants_table, Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { + if (Z_TYPE_PP(value) == IS_CONSTANT_ARRAY || + Z_TYPE_PP(value) == IS_CONSTANT) { + 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 '%s'", Z_STRVAL(opline->op2.u.constant)); + } + + ZEND_VM_NEXT_OPCODE(); + } } static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -2799,6 +2659,40 @@ 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 */ + c.name = zend_strndup(Z_STRVAL_P(name), Z_STRLEN_P(name)); + c.name_len = Z_STRLEN_P(name)+1; + c.module_number = PHP_USER_CONSTANT; + + if (zend_register_constant(&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); @@ -3033,6 +2927,88 @@ static int ZEND_BOOL_XOR_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_CONST == IS_CONST && IS_TMP_VAR == IS_CONST) { + /* try a function in namespace */ + zend_op *op_data = opline+1; + + ZEND_VM_INC_OPCODE(); + + 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))==SUCCESS) { + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + + /* no function found. try a static method in class */ + ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL(opline->op1.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_TMP_VAR != IS_UNUSED) { + char *function_name_strval; + int function_name_strlen; + zend_bool is_const = (IS_TMP_VAR == IS_CONST); + zend_free_op free_op2; + + if (is_const) { + function_name_strval = Z_STRVAL(opline->op2.u.constant); + function_name_strlen = Z_STRLEN(opline->op2.u.constant); + } else { + function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(function_name) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); + function_name_strlen = function_name->value.str.len; + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval); + zval_dtor(free_op2.var); + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_TMP_VAR != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -3392,6 +3368,88 @@ static int ZEND_BOOL_XOR_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_CONST == IS_CONST && IS_VAR == IS_CONST) { + /* try a function in namespace */ + zend_op *op_data = opline+1; + + ZEND_VM_INC_OPCODE(); + + 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))==SUCCESS) { + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + + /* no function found. try a static method in class */ + ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL(opline->op1.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_VAR != IS_UNUSED) { + char *function_name_strval; + int function_name_strlen; + zend_bool is_const = (IS_VAR == IS_CONST); + zend_free_op free_op2; + + if (is_const) { + function_name_strval = Z_STRVAL(opline->op2.u.constant); + function_name_strlen = Z_STRLEN(opline->op2.u.constant); + } else { + function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(function_name) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); + function_name_strlen = function_name->value.str.len; + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval); + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_VAR != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -3517,6 +3575,88 @@ static int ZEND_INIT_ARRAY_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_CONST == IS_CONST && IS_UNUSED == IS_CONST) { + /* try a function in namespace */ + zend_op *op_data = opline+1; + + ZEND_VM_INC_OPCODE(); + + 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))==SUCCESS) { + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + + /* no function found. try a static method in class */ + ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL(opline->op1.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_UNUSED != IS_UNUSED) { + char *function_name_strval; + int function_name_strlen; + zend_bool is_const = (IS_UNUSED == IS_CONST); + + + if (is_const) { + function_name_strval = Z_STRVAL(opline->op2.u.constant); + function_name_strlen = Z_STRLEN(opline->op2.u.constant); + } else { + function_name = NULL; + + if (Z_TYPE_P(function_name) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); + function_name_strlen = function_name->value.str.len; + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval); + + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_UNUSED != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -3844,6 +3984,88 @@ static int ZEND_BOOL_XOR_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_CONST == IS_CONST && IS_CV == IS_CONST) { + /* try a function in namespace */ + zend_op *op_data = opline+1; + + ZEND_VM_INC_OPCODE(); + + 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))==SUCCESS) { + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + + /* no function found. try a static method in class */ + ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL(opline->op1.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_CV != IS_UNUSED) { + char *function_name_strval; + int function_name_strlen; + zend_bool is_const = (IS_CV == IS_CONST); + + + if (is_const) { + function_name_strval = Z_STRVAL(opline->op2.u.constant); + function_name_strlen = Z_STRLEN(opline->op2.u.constant); + } else { + function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); + + if (Z_TYPE_P(function_name) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); + function_name_strlen = function_name->value.str.len; + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval); + + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_CV != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -9327,6 +9549,88 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_VAR == IS_CONST && IS_CONST == IS_CONST) { + /* try a function in namespace */ + zend_op *op_data = opline+1; + + ZEND_VM_INC_OPCODE(); + + 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))==SUCCESS) { + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + + /* no function found. try a static method in class */ + ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL(opline->op1.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_CONST != IS_UNUSED) { + char *function_name_strval; + int function_name_strlen; + zend_bool is_const = (IS_CONST == IS_CONST); + + + if (is_const) { + function_name_strval = Z_STRVAL(opline->op2.u.constant); + function_name_strlen = Z_STRLEN(opline->op2.u.constant); + } else { + function_name = &opline->op2.u.constant; + + if (Z_TYPE_P(function_name) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); + function_name_strlen = function_name->value.str.len; + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval); + + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_CONST != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -9358,6 +9662,73 @@ static int ZEND_CASE_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + + if (IS_VAR == IS_UNUSED) { + if (!zend_get_constant(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { + 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; + zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); + } + ZEND_VM_NEXT_OPCODE(); + } else { + zend_class_entry *ce; + zval **value; + + if (IS_VAR == IS_CONST) { + zend_op *op_data = opline + 1; + zend_constant *c; + + ZEND_VM_INC_OPCODE(); + + /* try a constant in namespace */ + if (zend_hash_quick_find(EG(zend_constants), Z_STRVAL(op_data->op1.u.constant), Z_STRLEN(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_get_constant(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { + 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; + 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_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL(opline->op2.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + + if (zend_hash_find(&ce->constants_table, Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { + if (Z_TYPE_PP(value) == IS_CONSTANT_ARRAY || + Z_TYPE_PP(value) == IS_CONSTANT) { + 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 '%s'", Z_STRVAL(opline->op2.u.constant)); + } + + ZEND_VM_NEXT_OPCODE(); + } +} + static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -10814,6 +11185,88 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_VAR == IS_CONST && IS_TMP_VAR == IS_CONST) { + /* try a function in namespace */ + zend_op *op_data = opline+1; + + ZEND_VM_INC_OPCODE(); + + 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))==SUCCESS) { + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + + /* no function found. try a static method in class */ + ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL(opline->op1.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_TMP_VAR != IS_UNUSED) { + char *function_name_strval; + int function_name_strlen; + zend_bool is_const = (IS_TMP_VAR == IS_CONST); + zend_free_op free_op2; + + if (is_const) { + function_name_strval = Z_STRVAL(opline->op2.u.constant); + function_name_strlen = Z_STRLEN(opline->op2.u.constant); + } else { + function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(function_name) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); + function_name_strlen = function_name->value.str.len; + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval); + zval_dtor(free_op2.var); + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_TMP_VAR != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -12340,6 +12793,88 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_VAR == IS_CONST && IS_VAR == IS_CONST) { + /* try a function in namespace */ + zend_op *op_data = opline+1; + + ZEND_VM_INC_OPCODE(); + + 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))==SUCCESS) { + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + + /* no function found. try a static method in class */ + ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL(opline->op1.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_VAR != IS_UNUSED) { + char *function_name_strval; + int function_name_strlen; + zend_bool is_const = (IS_VAR == IS_CONST); + zend_free_op free_op2; + + if (is_const) { + function_name_strval = Z_STRVAL(opline->op2.u.constant); + function_name_strlen = Z_STRLEN(opline->op2.u.constant); + } else { + function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); + + if (Z_TYPE_P(function_name) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); + function_name_strlen = function_name->value.str.len; + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval); + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_VAR != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -13069,6 +13604,88 @@ static int ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_VAR == IS_CONST && IS_UNUSED == IS_CONST) { + /* try a function in namespace */ + zend_op *op_data = opline+1; + + ZEND_VM_INC_OPCODE(); + + 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))==SUCCESS) { + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + + /* no function found. try a static method in class */ + ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL(opline->op1.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_UNUSED != IS_UNUSED) { + char *function_name_strval; + int function_name_strlen; + zend_bool is_const = (IS_UNUSED == IS_CONST); + + + if (is_const) { + function_name_strval = Z_STRVAL(opline->op2.u.constant); + function_name_strlen = Z_STRLEN(opline->op2.u.constant); + } else { + function_name = NULL; + + if (Z_TYPE_P(function_name) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); + function_name_strlen = function_name->value.str.len; + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval); + + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_UNUSED != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -14296,6 +14913,88 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) ZEND_VM_NEXT_OPCODE(); } +static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_op *opline = EX(opline); + zval *function_name; + zend_class_entry *ce; + + zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL); + + if (IS_VAR == IS_CONST && IS_CV == IS_CONST) { + /* try a function in namespace */ + zend_op *op_data = opline+1; + + ZEND_VM_INC_OPCODE(); + + 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))==SUCCESS) { + EX(object) = NULL; + ZEND_VM_NEXT_OPCODE(); + } + + /* no function found. try a static method in class */ + ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error(E_ERROR, "Class '%s' not found", Z_STRVAL(opline->op1.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + if(IS_CV != IS_UNUSED) { + char *function_name_strval; + int function_name_strlen; + zend_bool is_const = (IS_CV == IS_CONST); + + + if (is_const) { + function_name_strval = Z_STRVAL(opline->op2.u.constant); + function_name_strlen = Z_STRLEN(opline->op2.u.constant); + } else { + function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC); + + if (Z_TYPE_P(function_name) != IS_STRING) { + zend_error_noreturn(E_ERROR, "Function name must be a string"); + } + function_name_strval = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len); + function_name_strlen = function_name->value.str.len; + } + + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + + if (!is_const) { + efree(function_name_strval); + + } + } else { + if(!ce->constructor) { + zend_error_noreturn(E_ERROR, "Can not call constructor"); + } + if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { + zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); + } + EX(fbc) = ce->constructor; + } + + if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) { + EX(object) = NULL; + } else { + if (IS_CV != IS_UNUSED && + EG(This) && + Z_OBJ_HT_P(EG(This))->get_class_entry && + !instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) { + /* We are calling method of the other (incompatible) class, + but passing $this. This is done for compatibility with php-4. */ + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically, assuming $this from incompatible context", EX(fbc)->common.scope->name, EX(fbc)->common.function_name); + + } + if ((EX(object) = EG(This))) { + EX(object)->refcount++; + } + } + + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_CASE_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); @@ -15456,46 +16155,68 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_A static int ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); - zend_class_entry *ce = NULL; - 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_get_constant(opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len, &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { + if (!zend_get_constant(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", - opline->op2.u.constant.value.str.val, - opline->op2.u.constant.value.str.val); + Z_STRVAL(opline->op2.u.constant), + Z_STRVAL(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 { + zend_class_entry *ce; + zval **value; - ce = EX_T(opline->op1.u.var).class_entry; + if (IS_UNUSED == IS_CONST) { + zend_op *op_data = opline + 1; + zend_constant *c; - if (zend_hash_find(&ce->constants_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, (void **) &value) == SUCCESS) { - zend_class_entry *old_scope = EG(scope); + ZEND_VM_INC_OPCODE(); - 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 '%s'", opline->op2.u.constant.value.str.val); - } + /* try a constant in namespace */ + if (zend_hash_quick_find(EG(zend_constants), Z_STRVAL(op_data->op1.u.constant), Z_STRLEN(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_get_constant(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var TSRMLS_CC)) { + 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; + zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); + } + ZEND_VM_NEXT_OPCODE(); + } - ZEND_VM_NEXT_OPCODE(); + /* no constant found. try a constant in class */ + ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); + if (!ce) { + zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL(opline->op2.u.constant)); + } + } else { + ce = EX_T(opline->op1.u.var).class_entry; + } + + if (zend_hash_find(&ce->constants_table, Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { + if (Z_TYPE_PP(value) == IS_CONSTANT_ARRAY || + Z_TYPE_PP(value) == IS_CONSTANT) { + 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 '%s'", Z_STRVAL(opline->op2.u.constant)); + } + + ZEND_VM_NEXT_OPCODE(); + } } static int ZEND_INIT_ARRAY_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) @@ -29057,7 +29778,7 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, @@ -29397,31 +30118,31 @@ void zend_init_opcodes_handlers(void) ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_TMP_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_UNUSED_HANDLER, - ZEND_INIT_STATIC_METHOD_CALL_SPEC_CV_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER, + ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_HANDLER, ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_HANDLER, ZEND_ISSET_ISEMPTY_VAR_SPEC_CONST_HANDLER, @@ -30147,7 +30868,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 230e110973..82fbeda4f4 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -141,6 +141,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 |