=========================
original problem
=========================
the biggest problem caused by early class binding is that it's
unfriendly to opcode cachers.
parent1.php
class P
{
function __construct()
{
echo "parent2";
}
}
include "child.php"
==========
parent2.php
class P
{
function __construct()
{
echo "parent2";
}
}
include "child.php"
==========
child.php
class child extends P
{
}
new child();
without opcode cacher, when parent1.php is requested, "parent1" is
echoed, while parent2.php is requested "parent2" will be echoed.
but with opcode cachers, it always use the echo from first
requested/cached class P because when class child is being cached,
it's after "early class binding" and is binded with its parent class
P, the binding will not be done again after the child class is
restored from cache

=========================
other problems
=========================
read the sample coe first:
class MyException extends Exception
{
}

early class binding is done at compile time and opcode cachers will
only get binded not raw classes
the problem is that, the binded class MyException is has so many
handler pointers copied (inherited) from internal class Exception.
it's hard for a opcode cacher to cache such opcode data to disk, or
share with another instance of php which is not forked from the same
parent php process due to possible symbol relocation.

=========================
compatibility issue without early class binding
=========================
iirc the early class binding was removed but added back later due to
back compatibility issue:
if the class is early binded, code before class declaration can use class
new Foo(); // works
class Foo // early binding at compile time
{
}
but when there's no early binding
new Foo(); // error, undefined class
class Foo
{
}
// late class binding is done here at runtime

=========================
solution proposal
=========================
solution a: forget the back compatibility issue, early class binding
was deprecated and it's now gone.

solution b: add an api that allow extension/zend_extension disable
early class binding let opcode cachers decide to do nothing (which
mean the user should accept that, the early binding is gone), or to
redo the binding after restore from cache but before execution. when
no extension use this api, no behavior change.

pitfall for solution b: opcode cachers have to write their own scanner
to figure out which classes should be early binded and which opline
should be replaced with NOP

solution c: like solution b, but ZendEngine do most of the work, for
example: remember all the position/pointer to opline that might be
replaced with NOP, return from zend_compile_file or
zend_compile_string so opcode cachers will catch it. do early binding
after zend_compile_file/string, which also mean after opcode cacher
stuff
Tips for those don't know zend_compile_file/string:
zend_compile_file/string is a pointer that can be overloaded by
extension/zend_extension so one can hook into the compile time

=========================
PS
=========================
XCache tricked to disable early class binding by emptying
CG(class_table) before and restore it after compile so the compiler
won't see any class that isn't in the same file.

the reason i bring up this topic again before PHP_5_3 is out is
becuase 5.3 namespace patch breaks the XCache trick and i find it no
way to trick without changing php source:
5.3 namespace code will check for CG(class_table) and see if a class
is internal class to generate different code.
namespace ns;
e.g.:
class b extends Exception // will check ::Exception at runtime
{
}

class a extends c // always ns::c
{
}
with XCache enabled:
class b extends Exception // always ns::Exception because there's no
such internal class at compile time due to XCache trick.


sorry for the long post so i mark the sections with ===s that will
help your navigation

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to