]> granicus.if.org Git - php/commitdiff
Added support for Late Static Binding. (Dmitry, Etienne Kneuss)
authorDmitry Stogov <dmitry@php.net>
Sat, 29 Sep 2007 07:28:34 +0000 (07:28 +0000)
committerDmitry Stogov <dmitry@php.net>
Sat, 29 Sep 2007 07:28:34 +0000 (07:28 +0000)
30 files changed:
NEWS
Zend/tests/lsb_001.phpt [new file with mode: 0644]
Zend/tests/lsb_002.phpt [new file with mode: 0644]
Zend/tests/lsb_003.phpt [new file with mode: 0644]
Zend/tests/lsb_004.phpt [new file with mode: 0644]
Zend/tests/lsb_005.phpt [new file with mode: 0644]
Zend/tests/lsb_006.phpt [new file with mode: 0644]
Zend/tests/lsb_007.phpt [new file with mode: 0644]
Zend/tests/lsb_008.phpt [new file with mode: 0644]
Zend/tests/lsb_009.phpt [new file with mode: 0644]
Zend/tests/lsb_010.phpt [new file with mode: 0644]
Zend/tests/lsb_011.phpt [new file with mode: 0644]
Zend/tests/lsb_012.phpt [new file with mode: 0644]
Zend/tests/lsb_013.phpt [new file with mode: 0644]
Zend/tests/lsb_014.phpt [new file with mode: 0644]
Zend/tests/lsb_015.phpt [new file with mode: 0644]
Zend/tests/lsb_016.phpt [new file with mode: 0644]
Zend/tests/lsb_017.phpt [new file with mode: 0644]
Zend/zend_API.c
Zend/zend_builtin_functions.c
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_constants.c
Zend/zend_execute.c
Zend/zend_execute_API.c
Zend/zend_globals.h
Zend/zend_language_parser.y
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_execute.skl

diff --git a/NEWS b/NEWS
index c7b084d4f1ec435162bc06f3dd516d0d91411e5e..faca0c24686eb7dddc32b44cdd2a1fc34ffb1153 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? ??? 20??, PHP 5.3.0
 - Added support for namespaces. (Dmitry, Stas)
+- Added support for Late Static Binding. (Dmitry, Etienne Kneuss)
 - Added support for dynamic access of static members using $foo::myFunc().
   (Etienne Kneuss)
 
diff --git a/Zend/tests/lsb_001.phpt b/Zend/tests/lsb_001.phpt
new file mode 100644 (file)
index 0000000..20a2fd8
--- /dev/null
@@ -0,0 +1,61 @@
+--TEST--
+ZE2 Late Static Binding in a static function
+--FILE--
+<?php
+
+class TestClass {
+       protected static $staticVar = 'TestClassStatic';
+       const CLASS_CONST = 'TestClassConst';
+
+       protected static function staticFunction() {
+               return 'TestClassFunction';
+       }
+       
+       public static function testStaticVar() {
+               return static::$staticVar;
+       }
+
+       public static function testClassConst() {
+               return static::CLASS_CONST;
+       }
+
+       public static function testStaticFunction() {
+               return static::staticFunction();
+       }
+}
+
+class ChildClass1 extends TestClass {
+       protected static $staticVar = 'ChildClassStatic';
+       const CLASS_CONST = 'ChildClassConst';
+
+       protected static function staticFunction() {
+               return 'ChildClassFunction';
+       }
+}
+
+class ChildClass2 extends TestClass {}
+
+echo TestClass::testStaticVar() . "\n";
+echo TestClass::testClassConst() . "\n";
+echo TestClass::testStaticFunction() . "\n";
+
+echo ChildClass1::testStaticVar() . "\n";
+echo ChildClass1::testClassConst() . "\n";
+echo ChildClass1::testStaticFunction() . "\n";
+
+echo ChildClass2::testStaticVar() . "\n";
+echo ChildClass2::testClassConst() . "\n";
+echo ChildClass2::testStaticFunction() . "\n";
+?>
+==DONE==
+--EXPECTF--
+TestClassStatic
+TestClassConst
+TestClassFunction
+ChildClassStatic
+ChildClassConst
+ChildClassFunction
+TestClassStatic
+TestClassConst
+TestClassFunction
+==DONE==
diff --git a/Zend/tests/lsb_002.phpt b/Zend/tests/lsb_002.phpt
new file mode 100644 (file)
index 0000000..4fca6dd
--- /dev/null
@@ -0,0 +1,66 @@
+--TEST--
+ZE2 Late Static Binding in an instance function
+--FILE--
+<?php
+
+class TestClass {
+       protected static $staticVar = 'TestClassStatic';
+       const CLASS_CONST = 'TestClassConst';
+
+       protected static function staticFunction() {
+               return 'TestClassFunction';
+       }
+       
+       public function testStaticVar() {
+               return static::$staticVar;
+       }
+
+       public function testClassConst() {
+               return static::CLASS_CONST;
+       }
+
+       public function testStaticFunction() {
+               return static::staticFunction();
+       }
+}
+
+class ChildClass1 extends TestClass {
+       protected static $staticVar = 'ChildClassStatic';
+       const CLASS_CONST = 'ChildClassConst';
+
+       protected static function staticFunction() {
+               return 'ChildClassFunction';
+       }
+}
+
+class ChildClass2 extends TestClass {}
+
+$testClass = new TestClass();
+$childClass1 = new ChildClass1();
+$childClass2 = new ChildClass2();
+
+
+echo $testClass->testStaticVar() . "\n";
+echo $testClass->testClassConst() . "\n";
+echo $testClass->testStaticFunction() . "\n";
+
+echo $childClass1->testStaticVar() . "\n";
+echo $childClass1->testClassConst() . "\n";
+echo $childClass1->testStaticFunction() . "\n";
+
+echo $childClass2->testStaticVar() . "\n";
+echo $childClass2->testClassConst() . "\n";
+echo $childClass2->testStaticFunction() . "\n";
+?>
+==DONE==
+--EXPECTF--
+TestClassStatic
+TestClassConst
+TestClassFunction
+ChildClassStatic
+ChildClassConst
+ChildClassFunction
+TestClassStatic
+TestClassConst
+TestClassFunction
+==DONE==
diff --git a/Zend/tests/lsb_003.phpt b/Zend/tests/lsb_003.phpt
new file mode 100644 (file)
index 0000000..4e9fe1f
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+ZE2 Late Static Binding creating a new class with 'static'
+--FILE--
+<?php
+
+class TestClass {
+       public static function createInstance() {
+               return new static();
+       }
+}
+
+class ChildClass extends TestClass {}
+
+$testClass = TestClass::createInstance();
+$childClass = ChildClass::createInstance();
+
+echo get_class($testClass) . "\n";
+echo get_class($childClass) . "\n";
+?>
+==DONE==
+--EXPECTF--
+TestClass
+ChildClass
+==DONE==
diff --git a/Zend/tests/lsb_004.phpt b/Zend/tests/lsb_004.phpt
new file mode 100644 (file)
index 0000000..6baeba0
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+ZE2 Late Static Binding testing get_called_class()
+--FILE--
+<?php
+
+class TestClass {
+       public static function getClassName() {
+               return get_called_class();
+       }
+}
+
+class ChildClass extends TestClass {}
+
+echo TestClass::getClassName() . "\n";
+echo ChildClass::getClassName() . "\n";
+?>
+==DONE==
+--EXPECTF--
+TestClass
+ChildClass
+==DONE==
diff --git a/Zend/tests/lsb_005.phpt b/Zend/tests/lsb_005.phpt
new file mode 100644 (file)
index 0000000..00647a5
--- /dev/null
@@ -0,0 +1,51 @@
+--TEST--
+ZE2 Late Static Binding stacking static calleds
+--FILE--
+<?php
+
+class TestA {
+       public static function test() {
+               echo get_class(new static()) . "\n";
+               TestB::test();
+               echo get_class(new static()) . "\n";
+               TestC::test();
+               echo get_class(new static()) . "\n";
+               TestBB::test();
+               echo get_class(new static()) . "\n";
+       }
+}
+
+class TestB {
+       public static function test() {
+               echo get_class(new static()) . "\n";
+               TestC::test();
+               echo get_class(new static()) . "\n";
+       }
+}
+
+class TestC {
+       public static function test() {
+               echo get_class(new static()) . "\n";
+       }
+}
+
+class TestBB extends TestB {
+}
+
+TestA::test();
+
+?>
+==DONE==
+--EXPECTF--
+TestA
+TestB
+TestC
+TestB
+TestA
+TestC
+TestA
+TestBB
+TestC
+TestBB
+TestA
+==DONE==
diff --git a/Zend/tests/lsb_006.phpt b/Zend/tests/lsb_006.phpt
new file mode 100644 (file)
index 0000000..f5e2b04
--- /dev/null
@@ -0,0 +1,12 @@
+--TEST--
+ZE2 Late Static Binding ensuring extending 'static' is not allowed
+--FILE--
+<?php
+
+class Foo extends static {
+}
+
+?>
+==DONE==
+--EXPECTF--
+Fatal error: Cannot use 'static' as class name as it is reserved in %s on line %d
diff --git a/Zend/tests/lsb_007.phpt b/Zend/tests/lsb_007.phpt
new file mode 100644 (file)
index 0000000..a20a826
--- /dev/null
@@ -0,0 +1,12 @@
+--TEST--
+ZE2 Late Static Binding ensuring implementing 'static' is not allowed
+--FILE--
+<?php
+
+class Foo implements static {
+}
+
+?>
+==DONE==
+--EXPECTF--
+Fatal error: Cannot use 'static' as interface name as it is reserved in %s on line %d
diff --git a/Zend/tests/lsb_008.phpt b/Zend/tests/lsb_008.phpt
new file mode 100644 (file)
index 0000000..88507b3
--- /dev/null
@@ -0,0 +1,8 @@
+--TEST--
+ZE2 Late Static Binding class name "static"
+--FILE--
+<?php
+class static {
+}
+--EXPECTF--
+Parse error: syntax error, unexpected T_STATIC, expecting T_STRING in %slsb_008.php on line 2
diff --git a/Zend/tests/lsb_009.phpt b/Zend/tests/lsb_009.phpt
new file mode 100644 (file)
index 0000000..7bf3086
--- /dev/null
@@ -0,0 +1,8 @@
+--TEST--
+ZE2 Late Static Binding interface name "static"
+--FILE--
+<?php
+interface static {
+}
+--EXPECTF--
+Parse error: syntax error, unexpected T_STATIC, expecting T_STRING in %slsb_009.php on line 2
diff --git a/Zend/tests/lsb_010.phpt b/Zend/tests/lsb_010.phpt
new file mode 100644 (file)
index 0000000..2ac0306
--- /dev/null
@@ -0,0 +1,38 @@
+--TEST--
+ZE2 Late Static Binding using static:: in functions called by non execute() calls and constructors.
+--FILE--
+<?php
+
+class Foo {
+       protected static $className = 'Foo';
+       public static function bar() {
+               echo static::$className . "::bar\n";
+       }
+       public function __construct() {
+               echo static::$className . "::__construct\n";
+       }
+       public function __destruct() {
+               echo static::$className . "::__destruct\n";
+       }
+}
+
+class FooChild extends Foo {
+       protected static $className = 'FooChild';
+}
+
+register_shutdown_function(array('Foo', 'bar'));
+register_shutdown_function(array('FooChild', 'bar'));
+
+$foo = new Foo();
+$fooChild = new FooChild();
+unset($foo);
+unset($fooChild);
+
+?>
+--EXPECTF--
+Foo::__construct
+FooChild::__construct
+Foo::__destruct
+FooChild::__destruct
+Foo::bar
+FooChild::bar
diff --git a/Zend/tests/lsb_011.phpt b/Zend/tests/lsb_011.phpt
new file mode 100644 (file)
index 0000000..3c5bbbe
--- /dev/null
@@ -0,0 +1,23 @@
+--TEST--
+ZE2 Late Static Binding call to static::method() from internal function (array)
+--FILE--
+<?php
+
+class Test1 {
+       static function ok() {
+               echo "bug";
+       }
+       static function test() {
+               call_user_func(array("static","ok"));
+       }
+}
+
+class Test2 extends Test1 {
+       static function ok() {
+               echo "ok";
+       }
+}
+Test2::test();
+?>
+--EXPECT--
+ok
diff --git a/Zend/tests/lsb_012.phpt b/Zend/tests/lsb_012.phpt
new file mode 100644 (file)
index 0000000..3ac8d38
--- /dev/null
@@ -0,0 +1,23 @@
+--TEST--
+ZE2 Late Static Binding call to static::method() from internal function (string)
+--FILE--
+<?php
+
+class Test1 {
+       static function ok() {
+               echo "bug";
+       }
+       static function test() {
+               call_user_func("static::ok");
+       }
+}
+
+class Test2 extends Test1 {
+       static function ok() {
+               echo "ok";
+       }
+}
+Test2::test();
+?>
+--EXPECT--
+ok
diff --git a/Zend/tests/lsb_013.phpt b/Zend/tests/lsb_013.phpt
new file mode 100644 (file)
index 0000000..3f32dc3
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+ZE2 Late Static Binding is_callable() and static::method()
+--FILE--
+<?php
+
+class Test1 {
+       static function test() {
+               var_dump(is_callable("static::ok"));
+               var_dump(is_callable(array("static","ok")));
+       }
+}
+
+class Test2 extends Test1 {
+       static function ok() {
+       }
+}
+Test1::test();
+Test2::test();
+?>
+--EXPECT--
+bool(false)
+bool(false)
+bool(true)
+bool(true)
diff --git a/Zend/tests/lsb_014.phpt b/Zend/tests/lsb_014.phpt
new file mode 100644 (file)
index 0000000..34ee7b4
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--                               
+ZE2 Late Static Binding access to static::const through defined() anf get_constant()
+--FILE--
+<?php
+
+class Test1 {
+       static function test() {
+               var_dump(defined("static::ok"));
+               if (defined("static::ok")) {
+                       echo constant("static::ok");
+               }
+       }
+}
+
+class Test2 extends Test1 {
+       const ok = "ok";
+}
+Test1::test();
+Test2::test();
+?>
+--EXPECT--
+bool(false)
+bool(true)
+ok
diff --git a/Zend/tests/lsb_015.phpt b/Zend/tests/lsb_015.phpt
new file mode 100644 (file)
index 0000000..8077a4f
--- /dev/null
@@ -0,0 +1,92 @@
+--TEST--
+ZE2 Late Static Binding with exceptions 
+--FILE--
+<?php
+function foo() {
+    B::throwException();
+}
+class C {
+    public static function bla() {
+        B::throwException();
+    }
+    public static function getException() {
+        return new Exception();
+         
+    }
+}
+class A {
+
+    public static function throwException_after() {
+        C::bla();
+    }
+    public static function throwException() {
+        throw C::getException();
+    }
+    public static function test() {
+        static::who();
+    }
+    public static function who() {
+        echo "A\n";
+    }
+
+    public static function mycatch() {
+        try {
+            static::who();
+            B::throwException_after();
+        } catch(Exception $e) {
+            static::who();
+            A::test();
+            static::who();
+            B::test();
+            static::who();
+
+            self::simpleCatch();
+            static::who();
+        }
+    }
+
+    public static function simpleCatch() {
+        try {
+            static::who();
+            throw new Exception();
+        } catch (Exception $e) {
+            static::who();
+        }
+    }
+}
+
+class B extends A {
+    public static function who() {
+        echo "B\n";
+    }
+
+}
+
+echo "via A:\n";
+A::myCatch();
+echo "via B:\n";
+B::myCatch();
+?>
+==DONE==
+--EXPECTF--
+via A:
+A
+A
+A
+A
+B
+A
+A
+A
+A
+via B:
+B
+B
+A
+B
+B
+B
+A
+A
+B
+==DONE==
diff --git a/Zend/tests/lsb_016.phpt b/Zend/tests/lsb_016.phpt
new file mode 100644 (file)
index 0000000..f19c6aa
--- /dev/null
@@ -0,0 +1,41 @@
+--TEST--
+ZE2 Late Static Binding within hooks/magic methods
+--FILE--
+<?php
+
+class TestChild extends TestParent {
+
+    public static function who() {
+        echo __CLASS__."\n";
+    }
+}
+
+class TestParent {
+
+    public function __get($var) {
+        static::who();
+    }
+
+    public function __set($var, $val) {
+        static::who();
+    }
+
+    public function __call($name, $args) {
+        static::who();
+    }
+
+    public static function who() {
+        echo __CLASS__."\n";
+    }
+}
+$o = new TestChild;
+$o->test();
+$o->a = "b";
+echo $o->a;
+?>
+==DONE==
+--EXPECTF--
+TestChild
+TestChild
+TestChild
+==DONE==
diff --git a/Zend/tests/lsb_017.phpt b/Zend/tests/lsb_017.phpt
new file mode 100644 (file)
index 0000000..5f5ca43
--- /dev/null
@@ -0,0 +1,29 @@
+--TEST--
+ZE2 Late Static Binding nested calls
+--FILE--
+<?php
+class A {
+       public static function test($x=null) {
+               if (!is_null($x)) {
+                       echo "$x\n";
+               }
+               return get_called_class();
+       }
+}
+
+class B extends A {
+}
+class C extends A {
+}
+class D extends A {
+}
+
+echo A::test(B::test(C::test(D::test())))."\n";
+?>
+==DONE==
+--EXPECT--
+D
+C
+B
+A
+==DONE==
index 667b88cba34205ba757433aa8cd4bda54d95c090..184812941e602aa3a8266df2cfc3074daf7d33dc 100644 (file)
@@ -2306,10 +2306,13 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
                                                }
 
                                                lcname = zend_str_tolower_dup(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj));
-                                               if (Z_STRLEN_PP(obj) == sizeof("self") - 1 && memcmp(lcname, "self", sizeof("self")) == 0 && EG(active_op_array)) {
+                                               if (Z_STRLEN_PP(obj) == sizeof("self") - 1 && memcmp(lcname, "self", sizeof("self")-1) == 0 && EG(active_op_array)) {
                                                        ce = EG(active_op_array)->scope;
-                                               } else if (Z_STRLEN_PP(obj) == sizeof("parent") - 1 && memcmp(lcname, "parent", sizeof("parent")) == 0 && EG(active_op_array) && EG(active_op_array)->scope) {
+                                               } else if (Z_STRLEN_PP(obj) == sizeof("parent") - 1 && memcmp(lcname, "parent", sizeof("parent")-1) == 0 && EG(active_op_array) && EG(active_op_array)->scope) {
                                                        ce = EG(active_op_array)->scope->parent;
+                                               } else if (Z_STRLEN_PP(obj) == sizeof("static")-1 &&
+                                                          !memcmp(lcname, "static", sizeof("static")-1)) {
+                                                       ce = EG(called_scope);
                                                } else if (zend_lookup_class(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), &pce TSRMLS_CC) == SUCCESS) {
                                                        ce = *pce;
                                                }
index d4ead902ba057f28193975b962498aea3469002c..9a64ea72e40bf40f18d574f3f0853e0f60c666a3 100644 (file)
@@ -43,6 +43,7 @@ static ZEND_FUNCTION(error_reporting);
 static ZEND_FUNCTION(define);
 static ZEND_FUNCTION(defined);
 static ZEND_FUNCTION(get_class);
+static ZEND_FUNCTION(get_called_class);
 static ZEND_FUNCTION(get_parent_class);
 static ZEND_FUNCTION(method_exists);
 static ZEND_FUNCTION(property_exists);
@@ -103,6 +104,7 @@ static const zend_function_entry builtin_functions[] = {
        ZEND_FE(define,                         NULL)
        ZEND_FE(defined,                        NULL)
        ZEND_FE(get_class,                      NULL)
+       ZEND_FE(get_called_class,       NULL)
        ZEND_FE(get_parent_class,       NULL)
        ZEND_FE(method_exists,          NULL)
        ZEND_FE(property_exists,        NULL)
@@ -584,6 +586,25 @@ ZEND_FUNCTION(get_class)
 /* }}} */
 
 
+/* {{{ proto string get_called_class()
+   Retrieves the "Late Static Binding" class name */
+ZEND_FUNCTION(get_called_class)
+{
+       if (!ZEND_NUM_ARGS()) {
+               if (EG(called_scope)) {
+                       RETURN_STRINGL(EG(called_scope)->name, EG(called_scope)->name_length, 1);
+               } else {
+                       zend_error(E_WARNING, "get_called_class() called from outside a class");
+                       RETURN_FALSE;
+               }
+       } else {
+               ZEND_WRONG_PARAM_COUNT();
+               RETURN_FALSE;
+       }
+}
+/* }}} */
+
+
 /* {{{ proto string get_parent_class([mixed object])
    Retrieves the parent class name for object or class or current scope. */
 ZEND_FUNCTION(get_parent_class)
index 6924ea3976750874682c57fbed3700367da34e4a..e60df0435b20d7f1f276e4ce8be213b377c1db5d 100644 (file)
@@ -1564,6 +1564,7 @@ void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC)
                switch (fetch_type) {
                        case ZEND_FETCH_CLASS_SELF:
                        case ZEND_FETCH_CLASS_PARENT:
+                       case ZEND_FETCH_CLASS_STATIC:
                                SET_UNUSED(opline->op2);
                                opline->extended_value = fetch_type;
                                zval_dtor(&class_name->u.constant);
@@ -3008,6 +3009,9 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
                        case ZEND_FETCH_CLASS_PARENT:
                                zend_error(E_COMPILE_ERROR, "Cannot use 'parent' as class name as it is reserved");
                                break;
+                       case ZEND_FETCH_CLASS_STATIC:
+                               zend_error(E_COMPILE_ERROR, "Cannot use 'static' as class name as it is reserved");
+                               break;
                        default:
                                break;
                }
@@ -3115,6 +3119,9 @@ void zend_do_implements_interface(znode *interface_name TSRMLS_DC)
                case ZEND_FETCH_CLASS_PARENT:
                        zend_error(E_COMPILE_ERROR, "Cannot use 'parent' as interface name as it is reserved");
                        break;
+               case ZEND_FETCH_CLASS_STATIC:
+                       zend_error(E_COMPILE_ERROR, "Cannot use 'static' as interface name as it is reserved");
+                       break;
                default:
                        if (CG(active_op_array)->last > 0) {
                                opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
@@ -4499,6 +4506,9 @@ int zend_get_class_fetch_type(const char *class_name, uint class_name_len)
        } else if ((class_name_len == sizeof("parent")-1) &&
                !memcmp(class_name, "parent", sizeof("parent")-1)) {
                return ZEND_FETCH_CLASS_PARENT;
+       } else if ((class_name_len == sizeof("static")-1) &&
+               !memcmp(class_name, "static", sizeof("static")-1)) {
+               return ZEND_FETCH_CLASS_STATIC;
        } else {
                return ZEND_FETCH_CLASS_DEFAULT;
        }
index b7321a1f52621e658c49b87d6bdc19accda12e88..91657d86ee5527d1b9be9a627ab1c60e605034e6 100644 (file)
@@ -270,9 +270,7 @@ typedef union _zend_function {
 
 
 typedef struct _zend_function_state {
-       HashTable *function_symbol_table;
        zend_function *function;
-       void *reserved[ZEND_MAX_RESERVED_RESOURCES];
 } zend_function_state;
 
 
@@ -295,6 +293,7 @@ struct _zend_execute_data {
        struct _zend_op *opline;
        zend_function_state function_state;
        zend_function *fbc; /* Function Being Called */
+       zend_class_entry *called_scope;
        zend_op_array *op_array;
        zval *object;
        union _temp_variable *Ts;
@@ -597,6 +596,7 @@ 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_STATIC                7
 #define ZEND_FETCH_CLASS_RT_NS_CHECK 0x20
 #define ZEND_FETCH_CLASS_RT_NS_NAME  0x40
 #define ZEND_FETCH_CLASS_NO_AUTOLOAD 0x80
index 13f9ba98486f4423595b2d41179546f3331fdedf..2c0c57a7d8e2f944c1d882975564875b5988a821 100644 (file)
@@ -317,6 +317,14 @@ ZEND_API int zend_get_constant_ex(char *name, uint name_len, zval *result, zend_
                                ce = scope->parent;
                        }
                        efree(lcname);
+               } else if (class_name_len == sizeof("static")-1 &&
+                          !memcmp(lcname, "static", sizeof("static")-1)) {
+                       if (EG(called_scope)) {
+                               ce = EG(called_scope);
+                       } else {
+                               zend_error(E_ERROR, "Cannot access static:: when no class scope is active");
+                       }
+                       efree(lcname);
                } else {
                        /* Check for namespace constant */
                        char *nsname;
index 77a9ffbaf092178dd06a15a88782976fdffb3afb..32d47d0d5e951cee6168f8de9f3e75426a0ecc0b 100644 (file)
@@ -147,6 +147,17 @@ static inline void zend_pzval_unlock_free_func(zval *z)
 #define CV_OF(i)     (EG(current_execute_data)->CVs[i])
 #define CV_DEF_OF(i) (EG(active_op_array)->vars[i])
 
+#define CTOR_CALL_BIT    0x1
+#define CTOR_USED_BIT    0x2
+
+#define IS_CTOR_CALL(ce) (((zend_uintptr_t)(ce)) & CTOR_CALL_BIT)
+#define IS_CTOR_USED(ce) (((zend_uintptr_t)(ce)) & CTOR_USED_BIT)
+
+#define ENCODE_CTOR(ce, used) \
+       ((zend_class_entry*)(((zend_uintptr_t)(ce)) | CTOR_CALL_BIT | ((used) ? CTOR_USED_BIT : 0)))
+#define DECODE_CTOR(ce) \
+       ((zend_class_entry*)(((zend_uintptr_t)(ce)) & ~(CTOR_CALL_BIT|CTOR_USED_BIT)))
+
 ZEND_API zval** zend_get_compiled_variable_value(zend_execute_data *execute_data_ptr, zend_uint var)
 {
        return execute_data_ptr->CVs[var];
index c16e65d511d0ddf43eac46fa94442e74964f4df8..51577775668b46bec39cc46a9bc59d6d175a441d 100644 (file)
@@ -186,6 +186,7 @@ void init_executor(TSRMLS_D)
        EG(exception) = NULL;
 
        EG(scope) = NULL;
+       EG(called_scope) = NULL;
 
        EG(This) = NULL;
        
@@ -627,6 +628,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
        zend_op_array *original_op_array;
        zend_op **original_opline_ptr;
        zend_class_entry *current_scope;
+       zend_class_entry *current_called_scope;
        zend_class_entry *calling_scope = NULL;
        zend_class_entry *check_scope_or_static = NULL;
        zval *current_this;
@@ -729,6 +731,15 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
                                        found = (*ce != NULL?SUCCESS:FAILURE);
                                        fci->object_pp = EG(This)?&EG(This):NULL;
                                        EX(object) = EG(This);
+                               } else if (Z_STRLEN_PP(fci->object_pp) == sizeof("static")-1 &&
+                                          !memcmp(Z_STRVAL_PP(fci->object_pp), "static", sizeof("static")-1)) {
+                                       if (!EG(called_scope)) {
+                                               zend_error(E_ERROR, "Cannot access static:: when no class scope is active");
+                                       }
+                                       ce = &(EG(called_scope));
+                                       found = (*ce != NULL?SUCCESS:FAILURE);
+                                       fci->object_pp = EG(This)?&EG(This):NULL;
+                                       EX(object) = EG(This);
                                } else {
                                        zend_class_entry *scope;
                                        scope = EG(active_op_array) ? EG(active_op_array)->scope : NULL;
@@ -777,28 +788,24 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
                    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) {
+
+                               if (calling_scope && 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 (calling_scope && 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;
+                               } else if (clen == sizeof("static") - 1 && 
+                                          !memcmp(lcname, "static", sizeof("static")-1)) {
+                                       ce_child = EG(called_scope);
+                               } else 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);
                                }
+
                                if (!ce_child) {
                                        zend_error(E_ERROR, "Cannot call method %s() or method does not exist", fname);
                                        return FAILURE;
@@ -809,6 +816,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
                                fname = fname + clen + 2;
                                fname_len = mlen;
                        }
+                       efree(lcname);
 
                        if (fci->object_pp) {
                                if (Z_OBJ_HT_PP(fci->object_pp)->get_method == NULL) {
@@ -947,6 +955,13 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
 
        current_this = EG(This);
 
+       current_called_scope = EG(called_scope);
+       if (calling_scope) {
+               EG(called_scope) = calling_scope;
+       } else if (EX(function_state).function->type != ZEND_INTERNAL_FUNCTION) {
+               EG(called_scope) = NULL;
+       }
+           
        if (fci->object_pp) {
                if ((EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) {
                        EG(This) = NULL;
@@ -1023,6 +1038,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
        if (EG(This)) {
                zval_ptr_dtor(&EG(This));
        }
+       EG(called_scope) = current_called_scope;
        EG(scope) = current_scope;
        EG(This) = current_this;
        EG(current_execute_data) = EX(prev_execute_data);
@@ -1508,6 +1524,11 @@ check_fetch_type:
                                zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent");
                        }
                        return EG(scope)->parent;
+               case ZEND_FETCH_CLASS_STATIC:
+                       if (!EG(called_scope)) {
+                               zend_error(E_ERROR, "Cannot access static:: when no class scope is active");
+                       }
+                       return EG(called_scope);
                case ZEND_FETCH_CLASS_AUTO: {
                                fetch_type = zend_get_class_fetch_type(class_name, class_name_len);
                                if (fetch_type!=ZEND_FETCH_CLASS_DEFAULT) {
index 832053730cdf791f59d18d3a8ddb9951c5deba64..47c684522e31c352a729a6c5b7379b2fca728c53 100644 (file)
@@ -190,6 +190,7 @@ struct _zend_executor_globals {
        HashTable *zend_constants;      /* constants table */
 
        zend_class_entry *scope;
+       zend_class_entry *called_scope; /* Scope of the calling class */
 
        zval *This;
 
index 3edbbb2c0ba4aae56a4c547a7c4c7a5effac010f..338b37c958063cb5b4650aaf3f93269f195cbcba 100644 (file)
@@ -661,6 +661,7 @@ function_call:
 
 fully_qualified_class_name:
                T_STRING { $$ = $1; }
+       |       T_STATIC { $$.op_type = IS_CONST; ZVAL_STRINGL(&$$.u.constant, "static", sizeof("static")-1, 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); }
 ;
index 1ceae37139d77dd85763d117eeb3bb48a32098f8..917d7793e16eb3139db61d2a241dc00dc4097990 100644 (file)
@@ -1683,7 +1683,7 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV)
        int function_name_strlen;
        zend_free_op free_op1, free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
 
@@ -1710,6 +1710,8 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV)
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -1736,7 +1738,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) {
                /* try a function in namespace */
@@ -1792,6 +1794,8 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
                EX(fbc) = ce->constructor;
        }
 
+       EX(called_scope) = ce;  
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -1806,6 +1810,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUS
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(called_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -1821,7 +1826,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
        int function_name_strlen;
        zend_free_op free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (OP2_TYPE == IS_CONST) {
                function_name_strval = opline->op2.u.constant.value.str.val;
@@ -1878,11 +1883,12 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
 {
        zend_op *opline = EX(opline);
        zval **original_return_value;
-       zend_class_entry *current_scope = NULL;
-       zval *current_this = NULL;
+       zend_class_entry *current_scope;
+       zend_class_entry *current_called_scope;
+       zval *current_this;
        int return_value_used = RETURN_VALUE_USED(opline);
        zend_bool should_change_scope;
-       zend_op *ctor_opline;
+       zval *ex_object;
 
        if (EX(function_state).function->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) {
                if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) {
@@ -1896,41 +1902,39 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
                                EX(function_state).function->common.function_name);
                }
        }
+       if (EX(function_state).function->common.scope &&
+               !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC) &&
+               !EX(object)) {
+                       
+               if (EX(function_state).function->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
+                       /* FIXME: output identifiers properly */
+                       zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name);
+               } else {
+                       /* FIXME: output identifiers properly */
+                       zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name);
+               }
+       }
 
-       zend_ptr_stack_2_push(&EG(argument_stack), (void *)(zend_uintptr_t)opline->extended_value, NULL);
-
-       EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr;
-
-       if (EX(function_state).function->type == ZEND_USER_FUNCTION
-               || EX(function_state).function->common.scope) {
+       if (EX(function_state).function->type == ZEND_USER_FUNCTION ||
+           EX(function_state).function->common.scope) {
                should_change_scope = 1;
                current_this = EG(This);
-               EG(This) = EX(object);
                current_scope = EG(scope);
+               current_called_scope = EG(called_scope);
+               EG(This) = EX(object);
                EG(scope) = (EX(function_state).function->type == ZEND_USER_FUNCTION || !EX(object)) ? EX(function_state).function->common.scope : NULL;
+               EG(called_scope) = EX(called_scope);
        } else {
                should_change_scope = 0;
        }
 
-       EX_T(opline->result.u.var).var.fcall_returned_reference = 0;
+       zend_ptr_stack_3_pop(&EG(arg_types_stack), (void*)&EX(called_scope), (void**)&ex_object, (void**)&EX(fbc));
+       zend_ptr_stack_2_push(&EG(argument_stack), (void *)(zend_uintptr_t)opline->extended_value, NULL);
+
+       EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr;
+//     EX_T(opline->result.u.var).var.fcall_returned_reference = 0;
 
-       if (EX(function_state).function->common.scope) {
-               if (!EG(This) && !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) {
-                       int severity;
-                       char *severity_word;
-                       if (EX(function_state).function->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
-                               severity = E_STRICT;
-                               severity_word = "should not";
-                       } else {
-                               severity = E_ERROR;
-                               severity_word = "cannot";
-                       }
-                       zend_error(severity, "Non-static method %s::%s() %s be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name, severity_word);
-               }
-       }
        if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) {
-               unsigned char return_reference = EX(function_state).function->common.return_reference;
-
                ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr);
                INIT_ZVAL(*(EX_T(opline->result.u.var).var.ptr));
 
@@ -1966,21 +1970,23 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
                if (!return_value_used) {
                        zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr);
                } else {
-                       EX_T(opline->result.u.var).var.fcall_returned_reference = return_reference;
+                       EX_T(opline->result.u.var).var.fcall_returned_reference = EX(function_state).function->common.return_reference;
                }
        } else if (EX(function_state).function->type == ZEND_USER_FUNCTION) {
+               HashTable *function_symbol_table;
+
                EX_T(opline->result.u.var).var.ptr = NULL;
                if (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
                        /*printf("Cache hit!  Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/
-                       EX(function_state).function_symbol_table = *(EG(symtable_cache_ptr)--);
+                       function_symbol_table = *(EG(symtable_cache_ptr)--);
                } else {
-                       ALLOC_HASHTABLE(EX(function_state).function_symbol_table);
-                       zend_hash_init(EX(function_state).function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0);
-                       /*printf("Cache miss!  Initialized %x\n", function_state.function_symbol_table);*/
+                       ALLOC_HASHTABLE(function_symbol_table);
+                       zend_hash_init(function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0);
+                       /*printf("Cache miss!  Initialized %x\n", function_symbol_table);*/
                }
-               EG(active_symbol_table) = EX(function_state).function_symbol_table;
+               EG(active_symbol_table) = function_symbol_table;
                original_return_value = EG(return_value_ptr_ptr);
-               EG(return_value_ptr_ptr) = EX_T(opline->result.u.var).var.ptr_ptr;
+               EG(return_value_ptr_ptr) = &EX_T(opline->result.u.var).var.ptr;
                EG(active_op_array) = (zend_op_array *) EX(function_state).function;
 
                zend_execute(EG(active_op_array) TSRMLS_CC);
@@ -1999,13 +2005,13 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
                EG(active_op_array) = EX(op_array);
                EG(return_value_ptr_ptr)=original_return_value;
                if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
-                       zend_hash_destroy(EX(function_state).function_symbol_table);
-                       FREE_HASHTABLE(EX(function_state).function_symbol_table);
+                       zend_hash_destroy(function_symbol_table);
+                       FREE_HASHTABLE(function_symbol_table);
                } else {
                        /* clean before putting into the cache, since clean
                           could call dtors, which could use cached hash */
-                       zend_hash_clean(EX(function_state).function_symbol_table);
-                       *(++EG(symtable_cache_ptr)) = EX(function_state).function_symbol_table;
+                       zend_hash_clean(function_symbol_table);
+                       *(++EG(symtable_cache_ptr)) = function_symbol_table;
                }
                EG(active_symbol_table) = EX(symbol_table);
        } else { /* ZEND_OVERLOADED_FUNCTION */
@@ -2014,7 +2020,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
 
                        /* Not sure what should be done here if it's a static method */
                if (EX(object)) {
-                       Z_OBJ_HT_P(EX(object))->call_method(EX(fbc)->common.function_name, opline->extended_value, EX_T(opline->result.u.var).var.ptr, &EX_T(opline->result.u.var).var.ptr, EX(object), return_value_used TSRMLS_CC);
+                       Z_OBJ_HT_P(EX(object))->call_method(EX(function_state).function->common.function_name, opline->extended_value, EX_T(opline->result.u.var).var.ptr, &EX_T(opline->result.u.var).var.ptr, EX(object), return_value_used TSRMLS_CC);
                } else {
                        zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object");
                }
@@ -2022,21 +2028,20 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
                if (EX(function_state).function->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
                        efree(EX(function_state).function->common.function_name);
                }
-               efree(EX(fbc));
+               efree(EX(function_state).function);
 
                if (!return_value_used) {
                        zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr);
                } else {
                        EX_T(opline->result.u.var).var.ptr->is_ref = 0;
                        EX_T(opline->result.u.var).var.ptr->refcount = 1;
+                       EX_T(opline->result.u.var).var.fcall_returned_reference = 0;
                }
        }
 
-       ctor_opline = (zend_op*)zend_ptr_stack_pop(&EG(arg_types_stack));
-
        if (EG(This)) {
-               if (EG(exception) && ctor_opline) {
-                       if (RETURN_VALUE_USED(ctor_opline)) {
+               if (EG(exception) && IS_CTOR_CALL(EX(called_scope))) {
+                       if (IS_CTOR_USED(EX(called_scope))) {
                                EG(This)->refcount--;
                        }
                        if (EG(This)->refcount == 1) {
@@ -2048,11 +2053,14 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
                }
        }
 
+       EX(object) = ex_object;
+       EX(called_scope) = DECODE_CTOR(EX(called_scope));
+
        if (should_change_scope) {
                EG(This) = current_this;
                EG(scope) = current_scope;
+               EG(called_scope) = current_called_scope;
        }
-       zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), (void**)&EX(fbc));
 
        EX(function_state).function = (zend_function *) EX(op_array);
        EG(function_state_ptr) = &EX(function_state);
@@ -2080,7 +2088,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY)
        zend_free_op free_op1;
        zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R);
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (zend_hash_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) {
                zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val);
@@ -2548,11 +2556,12 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY)
                EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr;
                EX_T(opline->result.u.var).var.ptr = object_zval;
 
-               zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), opline);
+               zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), ENCODE_CTOR(EX(called_scope), RETURN_VALUE_USED(opline)));
 
                /* We are not handling overloaded classes right now */
                EX(object) = object_zval;
                EX(fbc) = constructor;
+               EX(called_scope) = EX_T(opline->op1.u.var).class_entry;
 
                ZEND_VM_NEXT_OPCODE();
        }
@@ -3832,14 +3841,14 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
        }
 
        while (EX(fbc)) {
-               zend_op *ctor_opline = (zend_op*)zend_ptr_stack_pop(&EG(arg_types_stack));
-
+               EX(called_scope) = (zend_class_entry*)zend_ptr_stack_pop(&EG(arg_types_stack));
                if (EX(object)) {
-                       if (ctor_opline && RETURN_VALUE_USED(ctor_opline)) {
+                       if (IS_CTOR_USED(EX(called_scope))) {
                                EX(object)->refcount--;
                        }
                        zval_ptr_dtor(&EX(object));
                }
+               EX(called_scope) = DECODE_CTOR(EX(called_scope));
                zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), (void**)&EX(fbc));
        }
 
index 2df3ee8e313e54b94b987aa9487faf39ddbf15af..9baff66e72c33589053cac50c1da693976f930ec 100644 (file)
@@ -42,6 +42,7 @@ ZEND_API void execute(zend_op_array *op_array TSRMLS_DC)
 
        /* Initialize execute_data */
        EX(fbc) = NULL;
+       EX(called_scope) = NULL;
        EX(object) = NULL;
        EX(old_error_reporting) = NULL;
        if (op_array->T < TEMP_VAR_STACK_LIMIT) {
@@ -75,12 +76,6 @@ ZEND_API void execute(zend_op_array *op_array TSRMLS_DC)
 
        EX(function_state).function = (zend_function *) op_array;
        EG(function_state_ptr) = &EX(function_state);
-#if ZEND_DEBUG
-       /* function_state.function_symbol_table is saved as-is to a stack,
-        * which is an intentional UMR.  Shut it up if we're in DEBUG.
-        */
-       EX(function_state).function_symbol_table = NULL;
-#endif
        
        while (1) {
 #ifdef ZEND_WIN32
@@ -126,11 +121,12 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
 {
        zend_op *opline = EX(opline);
        zval **original_return_value;
-       zend_class_entry *current_scope = NULL;
-       zval *current_this = NULL;
+       zend_class_entry *current_scope;
+       zend_class_entry *current_called_scope;
+       zval *current_this;
        int return_value_used = RETURN_VALUE_USED(opline);
        zend_bool should_change_scope;
-       zend_op *ctor_opline;
+       zval *ex_object;
 
        if (EX(function_state).function->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) {
                if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) {
@@ -144,41 +140,39 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
                                EX(function_state).function->common.function_name);
                }
        }
+       if (EX(function_state).function->common.scope &&
+               !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC) &&
+               !EX(object)) {
 
-       zend_ptr_stack_2_push(&EG(argument_stack), (void *)(zend_uintptr_t)opline->extended_value, NULL);
-
-       EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr;
+               if (EX(function_state).function->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
+                       /* FIXME: output identifiers properly */
+                       zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name);
+               } else {
+                       /* FIXME: output identifiers properly */
+                       zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name);
+               }
+       }
 
-       if (EX(function_state).function->type == ZEND_USER_FUNCTION
-               || EX(function_state).function->common.scope) {
+       if (EX(function_state).function->type == ZEND_USER_FUNCTION ||
+           EX(function_state).function->common.scope) {
                should_change_scope = 1;
                current_this = EG(This);
-               EG(This) = EX(object);
                current_scope = EG(scope);
+               current_called_scope = EG(called_scope);
+               EG(This) = EX(object);
                EG(scope) = (EX(function_state).function->type == ZEND_USER_FUNCTION || !EX(object)) ? EX(function_state).function->common.scope : NULL;
+               EG(called_scope) = EX(called_scope);
        } else {
                should_change_scope = 0;
        }
 
-       EX_T(opline->result.u.var).var.fcall_returned_reference = 0;
+       zend_ptr_stack_3_pop(&EG(arg_types_stack), (void*)&EX(called_scope), (void**)&ex_object, (void**)&EX(fbc));
+       zend_ptr_stack_2_push(&EG(argument_stack), (void *)(zend_uintptr_t)opline->extended_value, NULL);
 
-       if (EX(function_state).function->common.scope) {
-               if (!EG(This) && !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC)) {
-                       int severity;
-                       char *severity_word;
-                       if (EX(function_state).function->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
-                               severity = E_STRICT;
-                               severity_word = "should not";
-                       } else {
-                               severity = E_ERROR;
-                               severity_word = "cannot";
-                       }
-                       zend_error(severity, "Non-static method %s::%s() %s be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name, severity_word);
-               }
-       }
-       if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) {
-               unsigned char return_reference = EX(function_state).function->common.return_reference;
+       EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr;
+//     EX_T(opline->result.u.var).var.fcall_returned_reference = 0;
 
+       if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) {
                ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr);
                INIT_ZVAL(*(EX_T(opline->result.u.var).var.ptr));
 
@@ -214,21 +208,23 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
                if (!return_value_used) {
                        zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr);
                } else {
-                       EX_T(opline->result.u.var).var.fcall_returned_reference = return_reference;
+                       EX_T(opline->result.u.var).var.fcall_returned_reference = EX(function_state).function->common.return_reference;
                }
        } else if (EX(function_state).function->type == ZEND_USER_FUNCTION) {
+               HashTable *function_symbol_table;
+
                EX_T(opline->result.u.var).var.ptr = NULL;
                if (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
                        /*printf("Cache hit!  Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/
-                       EX(function_state).function_symbol_table = *(EG(symtable_cache_ptr)--);
+                       function_symbol_table = *(EG(symtable_cache_ptr)--);
                } else {
-                       ALLOC_HASHTABLE(EX(function_state).function_symbol_table);
-                       zend_hash_init(EX(function_state).function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0);
-                       /*printf("Cache miss!  Initialized %x\n", function_state.function_symbol_table);*/
+                       ALLOC_HASHTABLE(function_symbol_table);
+                       zend_hash_init(function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0);
+                       /*printf("Cache miss!  Initialized %x\n", function_symbol_table);*/
                }
-               EG(active_symbol_table) = EX(function_state).function_symbol_table;
+               EG(active_symbol_table) = function_symbol_table;
                original_return_value = EG(return_value_ptr_ptr);
-               EG(return_value_ptr_ptr) = EX_T(opline->result.u.var).var.ptr_ptr;
+               EG(return_value_ptr_ptr) = &EX_T(opline->result.u.var).var.ptr;
                EG(active_op_array) = (zend_op_array *) EX(function_state).function;
 
                zend_execute(EG(active_op_array) TSRMLS_CC);
@@ -247,13 +243,13 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
                EG(active_op_array) = EX(op_array);
                EG(return_value_ptr_ptr)=original_return_value;
                if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
-                       zend_hash_destroy(EX(function_state).function_symbol_table);
-                       FREE_HASHTABLE(EX(function_state).function_symbol_table);
+                       zend_hash_destroy(function_symbol_table);
+                       FREE_HASHTABLE(function_symbol_table);
                } else {
                        /* clean before putting into the cache, since clean
                           could call dtors, which could use cached hash */
-                       zend_hash_clean(EX(function_state).function_symbol_table);
-                       *(++EG(symtable_cache_ptr)) = EX(function_state).function_symbol_table;
+                       zend_hash_clean(function_symbol_table);
+                       *(++EG(symtable_cache_ptr)) = function_symbol_table;
                }
                EG(active_symbol_table) = EX(symbol_table);
        } else { /* ZEND_OVERLOADED_FUNCTION */
@@ -262,7 +258,7 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
 
                        /* Not sure what should be done here if it's a static method */
                if (EX(object)) {
-                       Z_OBJ_HT_P(EX(object))->call_method(EX(fbc)->common.function_name, opline->extended_value, EX_T(opline->result.u.var).var.ptr, &EX_T(opline->result.u.var).var.ptr, EX(object), return_value_used TSRMLS_CC);
+                       Z_OBJ_HT_P(EX(object))->call_method(EX(function_state).function->common.function_name, opline->extended_value, EX_T(opline->result.u.var).var.ptr, &EX_T(opline->result.u.var).var.ptr, EX(object), return_value_used TSRMLS_CC);
                } else {
                        zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object");
                }
@@ -270,21 +266,20 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
                if (EX(function_state).function->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
                        efree(EX(function_state).function->common.function_name);
                }
-               efree(EX(fbc));
+               efree(EX(function_state).function);
 
                if (!return_value_used) {
                        zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr);
                } else {
                        EX_T(opline->result.u.var).var.ptr->is_ref = 0;
                        EX_T(opline->result.u.var).var.ptr->refcount = 1;
+                       EX_T(opline->result.u.var).var.fcall_returned_reference = 0;
                }
        }
 
-       ctor_opline = (zend_op*)zend_ptr_stack_pop(&EG(arg_types_stack));
-
        if (EG(This)) {
-               if (EG(exception) && ctor_opline) {
-                       if (RETURN_VALUE_USED(ctor_opline)) {
+               if (EG(exception) && IS_CTOR_CALL(EX(called_scope))) {
+                       if (IS_CTOR_USED(EX(called_scope))) {
                                EG(This)->refcount--;
                        }
                        if (EG(This)->refcount == 1) {
@@ -296,11 +291,14 @@ static int zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
                }
        }
 
+       EX(object) = ex_object;
+       EX(called_scope) = DECODE_CTOR(EX(called_scope));
+
        if (should_change_scope) {
                EG(This) = current_this;
                EG(scope) = current_scope;
+               EG(called_scope) = current_called_scope;
        }
-       zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), (void**)&EX(fbc));
 
        EX(function_state).function = (zend_function *) EX(op_array);
        EG(function_state_ptr) = &EX(function_state);
@@ -421,11 +419,12 @@ static int ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr;
                EX_T(opline->result.u.var).var.ptr = object_zval;
 
-               zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), opline);
+               zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), ENCODE_CTOR(EX(called_scope), RETURN_VALUE_USED(opline)));
 
                /* We are not handling overloaded classes right now */
                EX(object) = object_zval;
                EX(fbc) = constructor;
+               EX(called_scope) = EX_T(opline->op1.u.var).class_entry;
 
                ZEND_VM_NEXT_OPCODE();
        }
@@ -554,14 +553,14 @@ static int ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        }
 
        while (EX(fbc)) {
-               zend_op *ctor_opline = (zend_op*)zend_ptr_stack_pop(&EG(arg_types_stack));
-
+               EX(called_scope) = (zend_class_entry*)zend_ptr_stack_pop(&EG(arg_types_stack));
                if (EX(object)) {
-                       if (ctor_opline && RETURN_VALUE_USED(ctor_opline)) {
+                       if (IS_CTOR_USED(EX(called_scope))) {
                                EX(object)->refcount--;
                        }
                        zval_ptr_dtor(&EX(object));
                }
+               EX(called_scope) = DECODE_CTOR(EX(called_scope));
                zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), (void**)&EX(fbc));
        }
 
@@ -665,7 +664,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
 
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_CONST == IS_CONST) {
                function_name_strval = opline->op2.u.constant.value.str.val;
@@ -824,7 +823,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
        zend_free_op free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_TMP_VAR == IS_CONST) {
                function_name_strval = opline->op2.u.constant.value.str.val;
@@ -940,7 +939,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
        zend_free_op free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_VAR == IS_CONST) {
                function_name_strval = opline->op2.u.constant.value.str.val;
@@ -1084,7 +1083,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
 
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_CV == IS_CONST) {
                function_name_strval = opline->op2.u.constant.value.str.val;
@@ -1427,7 +1426,7 @@ static int ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 
        zval *fname = &opline->op1.u.constant;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (zend_hash_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) {
                zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val);
@@ -2392,7 +2391,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HAN
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_CONST == IS_CONST && IS_CONST == IS_CONST) {
                /* try a function in namespace */
@@ -2448,6 +2447,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HAN
                EX(fbc) = ce->constructor;
        }
 
+       EX(called_scope) = ce;
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -2462,6 +2463,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HAN
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(called_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -2933,7 +2935,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDL
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_CONST == IS_CONST && IS_TMP_VAR == IS_CONST) {
                /* try a function in namespace */
@@ -2989,6 +2991,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDL
                EX(fbc) = ce->constructor;
        }
 
+       EX(called_scope) = ce;
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -3003,6 +3007,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDL
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(called_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -3374,7 +3379,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDL
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_CONST == IS_CONST && IS_VAR == IS_CONST) {
                /* try a function in namespace */
@@ -3430,6 +3435,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDL
                EX(fbc) = ce->constructor;
        }
 
+       EX(called_scope) = ce;
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -3444,6 +3451,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDL
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(called_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -3581,7 +3589,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HA
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_CONST == IS_CONST && IS_UNUSED == IS_CONST) {
                /* try a function in namespace */
@@ -3637,6 +3645,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HA
                EX(fbc) = ce->constructor;
        }
 
+       EX(called_scope) = ce;
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -3651,6 +3661,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HA
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(called_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -3990,7 +4001,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLE
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_CONST == IS_CONST && IS_CV == IS_CONST) {
                /* try a function in namespace */
@@ -4046,6 +4057,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLE
                EX(fbc) = ce->constructor;
        }
 
+       EX(called_scope) = ce;
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -4060,6 +4073,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLE
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(called_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -5473,7 +5487,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        int function_name_strlen;
        zend_free_op free_op1;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = &opline->op2.u.constant;
 
@@ -5500,6 +5514,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -5916,7 +5932,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
        zend_free_op free_op1, free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC);
 
@@ -5943,6 +5959,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -6361,7 +6379,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
        zend_free_op free_op1, free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC);
 
@@ -6388,6 +6406,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -6898,7 +6918,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
        zend_free_op free_op1;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC);
 
@@ -6925,6 +6945,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -9503,7 +9525,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        int function_name_strlen;
        zend_free_op free_op1;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = &opline->op2.u.constant;
 
@@ -9530,6 +9552,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -9555,7 +9579,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDL
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_VAR == IS_CONST && IS_CONST == IS_CONST) {
                /* try a function in namespace */
@@ -9611,6 +9635,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDL
                EX(fbc) = ce->constructor;
        }
 
+       EX(called_scope) = ce;
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -9625,6 +9651,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDL
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(called_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -11138,7 +11165,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
        zend_free_op free_op1, free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC);
 
@@ -11165,6 +11192,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -11191,7 +11220,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_VAR == IS_CONST && IS_TMP_VAR == IS_CONST) {
                /* try a function in namespace */
@@ -11247,6 +11276,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER
                EX(fbc) = ce->constructor;
        }
 
+       EX(called_scope) = ce;
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -11261,6 +11292,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(called_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -12746,7 +12778,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
        zend_free_op free_op1, free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC);
 
@@ -12773,6 +12805,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -12799,7 +12833,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_VAR == IS_CONST && IS_VAR == IS_CONST) {
                /* try a function in namespace */
@@ -12855,6 +12889,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER
                EX(fbc) = ce->constructor;
        }
 
+       EX(called_scope) = ce;
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -12869,6 +12905,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(called_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -13610,7 +13647,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HAND
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_VAR == IS_CONST && IS_UNUSED == IS_CONST) {
                /* try a function in namespace */
@@ -13666,6 +13703,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HAND
                EX(fbc) = ce->constructor;
        }
 
+       EX(called_scope) = ce;
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -13680,6 +13719,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HAND
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(called_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -14867,7 +14907,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
        zend_free_op free_op1;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC);
 
@@ -14894,6 +14934,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -14919,7 +14961,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        if (IS_VAR == IS_CONST && IS_CV == IS_CONST) {
                /* try a function in namespace */
@@ -14975,6 +15017,8 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_
                EX(fbc) = ce->constructor;
        }
 
+       EX(called_scope) = ce;
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -14989,6 +15033,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(called_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -16107,7 +16152,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
        int function_name_strlen;
 
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = &opline->op2.u.constant;
 
@@ -16134,6 +16179,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -17137,7 +17184,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
        int function_name_strlen;
        zend_free_op free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC);
 
@@ -17164,6 +17211,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -18101,7 +18150,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
        int function_name_strlen;
        zend_free_op free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC);
 
@@ -18128,6 +18177,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -19330,7 +19381,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        int function_name_strlen;
 
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC);
 
@@ -19357,6 +19408,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -21914,7 +21967,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
 
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = &opline->op2.u.constant;
 
@@ -21941,6 +21994,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -23392,7 +23447,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
        zend_free_op free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC);
 
@@ -23419,6 +23474,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -24909,7 +24966,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
        zend_free_op free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC);
 
@@ -24936,6 +24993,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -26856,7 +26915,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        int function_name_strlen;
 
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
 
        function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R TSRMLS_CC);
 
@@ -26883,6 +26942,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
index e1924a90c7b4f020f58491830b5c35c979f526de..6858f7635135e18f15906b5540fdd4c360632b34 100644 (file)
@@ -13,6 +13,7 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC)
 
        /* Initialize execute_data */
        EX(fbc) = NULL;
+       EX(called_scope) = NULL;
        EX(object) = NULL;
        EX(old_error_reporting) = NULL;
        if (op_array->T < TEMP_VAR_STACK_LIMIT) {
@@ -46,12 +47,6 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC)
 
        EX(function_state).function = (zend_function *) op_array;
        EG(function_state_ptr) = &EX(function_state);
-#if ZEND_DEBUG
-       /* function_state.function_symbol_table is saved as-is to a stack,
-        * which is an intentional UMR.  Shut it up if we're in DEBUG.
-        */
-       EX(function_state).function_symbol_table = NULL;
-#endif
        
        while (1) {
     {%ZEND_VM_CONTINUE_LABEL%}