]> granicus.if.org Git - php/commitdiff
Late Static Binding (Dmitry, Etienne Kneuss)
authorDmitry Stogov <dmitry@php.net>
Wed, 26 Sep 2007 07:16:33 +0000 (07:16 +0000)
committerDmitry Stogov <dmitry@php.net>
Wed, 26 Sep 2007 07:16:33 +0000 (07:16 +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 625dde1a47ddee60417d87499475839fb0328673..3b1c9db6131f4baa97be5bd746a723a98b9adc20 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ PHP                                                                        NEWS
 ?? ??? 20??, PHP 6.0
 - Unicode support. (Andrei, Dmitry, et al)
 - Namespaces. (Dmitry, Stas)
+- Late Static Binding (Dmitry, Etienne Kneuss)
 
 - Changed dl() to be disabled by default. Enabled only when explicitly 
   registered by the SAPI layer. Enabled only with CLI, CGI and EMBED. (Dmitry)
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 09863d26858cc11ad3a0409a06cca0e0ddfbd4ba..7a5f3892d419c198dc200e1a9481d7f07594d64a 100644 (file)
@@ -2860,6 +2860,9 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, zval *c
                                                        lcname_len == sizeof("parent")-1 &&
                                                        ZEND_U_EQUAL(Z_TYPE_PP(obj), lcname, lcname_len, "parent", sizeof("parent")-1)) {
                                                        ce = EG(active_op_array)->scope->parent;
+                                               } else if (lcname_len == sizeof("static")-1 &&
+                                                       ZEND_U_EQUAL(Z_TYPE_PP(obj), lcname, lcname_len, "static", sizeof("static")-1)) {
+                                                       ce = EG(called_scope);
                                                } else if (zend_u_lookup_class(Z_TYPE_PP(obj), Z_UNIVAL_PP(obj), Z_UNILEN_PP(obj), &pce TSRMLS_CC) == SUCCESS) {
                                                        ce = *pce;
                                                }
index d5f764c5c099e9fe8a76c4c6622c93f8ef1663a8..059867e60cfa7f86880fdbfb7a5077ff55bc7943 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 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)
@@ -614,6 +616,27 @@ ZEND_FUNCTION(get_class)
 }
 /* }}} */
 
+/* {{{ proto string get_called_class()
+   Retrieves the class name */
+ZEND_FUNCTION(get_called_class)
+{
+       int dup;
+
+       if (!ZEND_NUM_ARGS()) {
+               if (EG(called_scope)) {
+                       RETURN_TEXTL(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]) U
    Retrieves the parent class name for object or class or current scope. */
 ZEND_FUNCTION(get_parent_class)
index dc7b2c7f1a3943fa97296413b6c246b1b862b8b9..bda7271ed653e99d1b4a424ca28111f3c2008a84 100644 (file)
@@ -1702,6 +1702,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);
@@ -3220,6 +3221,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;
                }
@@ -3332,6 +3336,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];
@@ -4876,6 +4883,9 @@ int zend_get_class_fetch_type(zend_uchar type, zstr class_name, uint class_name_
        } else if ((class_name_len == sizeof("parent")-1) &&
            ZEND_U_EQUAL(type, class_name, class_name_len, "parent", sizeof("parent")-1)) {
                return ZEND_FETCH_CLASS_PARENT;
+       } else if ((class_name_len == sizeof("static")-1) &&
+           ZEND_U_EQUAL(type, class_name, class_name_len, "static", sizeof("static")-1)) {
+               return ZEND_FETCH_CLASS_STATIC;
        } else {
                return ZEND_FETCH_CLASS_DEFAULT;
        }
index a8caf053f39094c48c77758152dce5ae0025daa5..6ae2bc5bcb4356d9cb1acc222d7c488ff0d58b95 100644 (file)
@@ -275,9 +275,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;
 
 
@@ -300,6 +298,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;
@@ -632,6 +631,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_FLAGS        0xF0
 #define ZEND_FETCH_CLASS_NO_NORMALIZE 0x10
 #define ZEND_FETCH_CLASS_RT_NS_CHECK  0x20
index 85bbc5e7289d1221a93b904aa2744795cded0e7d..06b25c3a20fd71e8ade8a4b3d9c5bf789262fa95 100644 (file)
@@ -382,6 +382,14 @@ ZEND_API int zend_u_get_constant_ex(zend_uchar type, zstr name, uint name_len, z
                                ce = scope->parent;
                        }
                        efree(lcname.v);
+               } else if (lcname_len == sizeof("static")-1 &&
+                          ZEND_U_EQUAL(type, lcname, lcname_len, "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.v);
                } else {
                        /* Check for namespace constant */
                        zstr nsname;
index 3d3a5fe43bbb747cdcccdd764f7a7ec8faa3a325..3663199b8e2b385c6dee70ee83ef34388d840dc3 100644 (file)
@@ -150,6 +150,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 76c31ce7d1547b659b7528036d795201932d445a..80312c406df02937b562356e97e56f3a355a976a 100644 (file)
@@ -201,6 +201,7 @@ void init_executor(TSRMLS_D) /* {{{ */
        EG(exception) = NULL;
 
        EG(scope) = NULL;
+       EG(called_scope) = NULL;
 
        EG(This) = NULL;
        
@@ -676,6 +677,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;
@@ -784,6 +786,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_UNILEN_PP(fci->object_pp) == sizeof("static")-1 &&
+                                   ZEND_U_EQUAL(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_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;
@@ -852,6 +863,9 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
                        } else if (calling_scope && clen == sizeof("parent") - 1 && 
                            ZEND_U_EQUAL(Z_TYPE_P(fci->function_name), lcname, clen, "parent", sizeof("parent")-1)) {
                                ce_child = EG(active_op_array) && EG(active_op_array)->scope ? EG(scope)->parent : NULL;
+                       } else if (clen == sizeof("static") - 1 && 
+                           ZEND_U_EQUAL(Z_TYPE_P(fci->function_name), lcname, clen, "static", sizeof("static")-1)) {
+                               ce_child = EG(called_scope);
                        } else if (zend_u_lookup_class_ex(Z_TYPE_P(fci->function_name), lcname, clen, Z_UNIVAL_P(fci->function_name), 0, &pce TSRMLS_CC) == SUCCESS) {
                                ce_child = *pce;
                        }
@@ -1028,6 +1042,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;
@@ -1109,6 +1130,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);
@@ -1679,6 +1701,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: {
                                if (do_normalize) {
                                        lcname = zend_u_str_case_fold(type, class_name, class_name_len, 1, &class_name_len);
index 95b5ea94f8f3cce5d04ee0a4679064c75383444c..89e2527a3129d1ea1a3b0c39814a8e740e311102 100644 (file)
@@ -185,6 +185,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 9b11308b1a0d754002c1624b7e77ffcc092dda71..bf6b472d2413773ef6cfed9042b3ccefaaa5b790 100644 (file)
@@ -670,6 +670,7 @@ function_call:
 
 fully_qualified_class_name:
                T_STRING { $$ = $1; }
+       |       T_STATIC { $$.op_type = IS_CONST; ZVAL_ASCII_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 043e9983eadb20b5915a2de152eb4da32ed31f53..abcd9fea4fec3c7104889cae14fa12760b1287a8 100644 (file)
@@ -1736,7 +1736,7 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV)
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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);
 
@@ -1763,6 +1763,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -1789,7 +1791,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 */
@@ -1850,6 +1852,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 {
@@ -1864,6 +1868,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));
                }
        }
 
@@ -1879,7 +1884,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV)
        unsigned int function_name_strlen, lcname_len;
        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 = &opline->op2.u.constant;
@@ -1956,11 +1961,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) {
@@ -1975,42 +1981,38 @@ 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 %v::%v() 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 %v::%v() 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);
 
-       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";
-                       }
-                       /* FIXME: output identifiers properly */
-                       zend_error(severity, "Non-static method %v::%v() %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;
 
+       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));
 
@@ -2046,21 +2048,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_u_hash_init(EX(function_state).function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode));
-                       /*printf("Cache miss!  Initialized %x\n", function_state.function_symbol_table);*/
+                       ALLOC_HASHTABLE(function_symbol_table);
+                       zend_u_hash_init(function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode));
+                       /*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);
@@ -2079,13 +2083,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 */
@@ -2094,7 +2098,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");
                }
@@ -2102,21 +2106,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.v);
                }
-               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) {
@@ -2128,11 +2131,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);
@@ -2160,7 +2166,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_u_hash_find(EG(function_table), Z_TYPE_P(fname), Z_UNIVAL_P(fname), Z_UNILEN_P(fname)+1, (void **) &EX(function_state).function)==FAILURE) {
                /* FIXME: output identifiers properly */
@@ -2631,11 +2637,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();
        }
@@ -4030,14 +4037,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 1756076a38b6446e3a38016cf64c88247a5b9998..0fafe11e82e64e971b38c88b3c04d9b22062a853 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
@@ -133,11 +128,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) {
@@ -152,42 +148,38 @@ 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 %v::%v() 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 %v::%v() 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);
+
+       EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr;
 
-       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";
-                       }
-                       /* FIXME: output identifiers properly */
-                       zend_error(severity, "Non-static method %v::%v() %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));
 
@@ -223,21 +215,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_u_hash_init(EX(function_state).function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode));
-                       /*printf("Cache miss!  Initialized %x\n", function_state.function_symbol_table);*/
+                       ALLOC_HASHTABLE(function_symbol_table);
+                       zend_u_hash_init(function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0, UG(unicode));
+                       /*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);
@@ -256,13 +250,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 */
@@ -271,7 +265,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");
                }
@@ -279,21 +273,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.v);
                }
-               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) {
@@ -305,11 +298,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);
@@ -431,11 +427,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();
        }
@@ -564,14 +561,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));
        }
 
@@ -676,7 +673,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        unsigned int function_name_strlen, lcname_len;
 
 
-       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 = &opline->op2.u.constant;
@@ -874,7 +871,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        unsigned int function_name_strlen, lcname_len;
        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 = &opline->op2.u.constant;
@@ -987,7 +984,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        unsigned int function_name_strlen, lcname_len;
        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 = &opline->op2.u.constant;
@@ -1129,7 +1126,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        unsigned int function_name_strlen, lcname_len;
 
 
-       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 = &opline->op2.u.constant;
@@ -1501,7 +1498,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_u_hash_find(EG(function_table), Z_TYPE_P(fname), Z_UNIVAL_P(fname), Z_UNILEN_P(fname)+1, (void **) &EX(function_state).function)==FAILURE) {
                /* FIXME: output identifiers properly */
@@ -2541,7 +2538,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 */
@@ -2602,6 +2599,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 {
@@ -2616,6 +2615,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));
                }
        }
 
@@ -3092,7 +3092,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 */
@@ -3153,6 +3153,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 {
@@ -3167,6 +3169,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));
                }
        }
 
@@ -3539,7 +3542,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 */
@@ -3600,6 +3603,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 {
@@ -3614,6 +3619,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));
                }
        }
 
@@ -3752,7 +3758,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 */
@@ -3813,6 +3819,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 {
@@ -3827,6 +3835,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));
                }
        }
 
@@ -4167,7 +4176,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 */
@@ -4228,6 +4237,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 {
@@ -4242,6 +4253,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));
                }
        }
 
@@ -5766,7 +5778,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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;
 
@@ -5793,6 +5805,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -6215,7 +6229,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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);
 
@@ -6242,6 +6256,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -6666,7 +6682,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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);
 
@@ -6693,6 +6709,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -7210,7 +7228,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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);
 
@@ -7237,6 +7255,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -9962,7 +9982,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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;
 
@@ -9989,6 +10009,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -10014,7 +10036,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 */
@@ -10075,6 +10097,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 {
@@ -10089,6 +10113,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));
                }
        }
 
@@ -11659,7 +11684,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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);
 
@@ -11686,6 +11711,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -11712,7 +11739,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 */
@@ -11773,6 +11800,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 {
@@ -11787,6 +11816,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));
                }
        }
 
@@ -13329,7 +13359,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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);
 
@@ -13356,6 +13386,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -13382,7 +13414,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 */
@@ -13443,6 +13475,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 {
@@ -13457,6 +13491,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));
                }
        }
 
@@ -14250,7 +14285,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 */
@@ -14311,6 +14346,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 {
@@ -14325,6 +14362,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));
                }
        }
 
@@ -15518,7 +15556,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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);
 
@@ -15545,6 +15583,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -15570,7 +15610,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 */
@@ -15631,6 +15671,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 {
@@ -15645,6 +15687,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));
                }
        }
 
@@ -16817,7 +16860,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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;
 
@@ -16844,6 +16887,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -17900,7 +17945,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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);
 
@@ -17927,6 +17972,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -18917,7 +18964,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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);
 
@@ -18944,6 +18991,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -20199,7 +20248,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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);
 
@@ -20226,6 +20275,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -22969,7 +23020,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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;
 
@@ -22996,6 +23047,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -24504,7 +24557,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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);
 
@@ -24531,6 +24584,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -26078,7 +26133,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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);
 
@@ -26105,6 +26160,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 %R() on a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(called_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -28083,7 +28140,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       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);
 
@@ -28110,6 +28167,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 %R() on a non-object", Z_TYPE_P(function_name), 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 5118a36a8956e9e53998bd4a59398d43b4a48201..137656779392f08fdce1b379e3fe2e24aea31a81 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%}