Resolve calling class from static parent method - php

I have to refactor some code from PHP 7 to PHP 8.2. I need to resolve, from a parent static method, the child class that calls it via call_user_func_array. But the syntax of callables has changed in PHP 8.2 and I can't find the correct syntax.
Similar functionality can be resolved with non-static methods via Reflection and invokeArgs, using the related object as argument. But I can't do the same with static methods. Or I can't figure out how to do it. And I can't find any solution on the web either.
The code I used with PHP 7 and my attempts with PHP 8.2.
Does anyone know the correct syntax I have to use?
#########
# PHP 7
#########
if (preg_match('#^7#', phpversion()))
{
class A {
public static function getClassName() {
return get_called_class() . ' '. implode(' ', func_get_args());
}
}
class B extends A {
public static function getClassName() {
# do anything else
return call_user_func_array([ 'parent', 'getClassName' ], func_get_args());
}
}
echo B::getClassName('-', 'Hello!') . "\n"; # I wish it returns 'B - Hello!'
}
#########
# PHP 8
#########
if (preg_match('#^8#', phpversion()))
{
class A {
public static function getClassName() {
return get_called_class() . ' ' . implode(' ', func_get_args());
}
}
class B extends A {
public static function getClassName() {
# do anything else
return call_user_func_array([ static::class, 'parent::getClassName' ], func_get_args()); # Deprecated. Returns 'B - Hello!'
return (new \ReflectionMethod(parent::class, 'getClassName'))->invokeArgs(null, func_get_args()); # Returns 'A - Hello!'. KO
return (new \ReflectionMethod(static::class, 'getClassName'))->invokeArgs(null, func_get_args()); # segmentation fault, infinite loop. Obvious.
return call_user_func_array([ parent::class, 'getClassName' ], func_get_args()); # Returns 'A - Hello!'. KO
return call_user_func_array([ 'parent', 'getClassName' ], func_get_args()); # Deprecated. Returns 'B - Hello!'
}
}
echo B::getClassName('-', 'Hello!') . "\n"; # I wish it returns 'B - Hello!'
}

I believe the cleanest solution is to just call the parent method with the spreaded function args parent::getClassName(...func_get_args())
class A {
public static function getClassName() {
return get_called_class() . ' ' . implode(' ', func_get_args());
}
}
class B extends A {
public static function getClassName() {
# do anything else
return parent::getClassName(...func_get_args());
}
}
echo B::getClassName('Hello!'); //'B - Hello!';

Related

PHP: can't change number of arguments in static function of same name in subclass

I am wondering whether I can create a static function in a subclass with the same name as a static function in a superclass, but with a different number of arguments. I have tried this, but get an error.
Anyone know why PHP is coded to give this error? I am using the latest version of PHP, PHP 8.0.2, in TermUX on Android.
Anyone know or have any suggestions, even from a software engineering standpoint, how to overcome this problem?
Thanks.
<?php
class Foo {
public static function greet($name) {
echo "Hi $name. This is Foo.\n";
}
}
class Bar {
public static function greet($name){
echo "Hi $name. This is Bar.\n";
}
}
class Baz extends Bar {
// changing number of arguments in static function of same name in subclass
// generates: Fatal error: Declaration of Baz::greet($name, $name2)
//must be compatible with Bar::greet($name)
public static function greet($name, $name2){
echo "Hi $name and $name2. This is Baz.\n";
}
}
Foo::greet("David");
Bar::Greet("Anne");
Baz::Greet("Bob", "Sue");
?>
Doesn't matter static method or not.
The php language with each subsequent version becomes more "typed". In previous version 7.- you will get warning instead. By the way php doesn't have "Method overloading" like in other languages.
You can use args param, like this:
<?php
class Foo {
public static function greet(...$args) {
echo "Hi $args[0]. This is Foo.\n";
}
}
class Bar {
public static function greet(...$args){
echo "Hi $args[0]. This is Bar.\n";
}
}
class Baz extends Bar {
public static function greet(...$args){
echo "Hi " . implode(' and ', $args) . ". This is Baz.\n";
}
}
Foo::greet("David");
Bar::Greet("Anne");
Baz::Greet("Bob", "Sue");
Or use array of params (or class, contained them)
<?php
class Foo {
public static function greet($params) {
echo "Hi " . $params['name1'] . ". This is Foo.\n";
}
}
class Bar {
public static function greet($params){
//you can use reset ;)
echo "Hi " . reset($params) . ". This is Bar.\n";
}
}
class Baz extends Bar {
public static function greet($params){
echo "Hi " . implode(' and ', $params) . " This is Baz.\n";
}
}
Foo::greet(["name1" => "David"]);
Bar::Greet(["name1" => "Anne"]);
Baz::Greet(["name1" => "Bob", "name2" => "Sue"]);

bind a callback to the beginning and end of a method [duplicate]

Class test{
function test1()
{
echo 'inside test1';
}
function test2()
{
echo 'test2';
}
function test3()
{
echo 'test3';
}
}
$obj = new test;
$obj->test2();//prints test2
$obj->test3();//prints test3
Now my question is,
How can i call another function before any called function execution?
In above case, how can i auto call 'test1' function for every another function call,
so that i can get the output as,
test1
test2
test1
test3
currently i am getting output as
test2
test3
I cannot call 'test1' function in
every function definition as there may
be many functions. I need a way to
auto call a function before calling
any function of a class.
Any alternative way would also be do.
Your best bet is the magic method __call, see below for example:
<?php
class test {
function __construct(){}
private function test1(){
echo "In test1", PHP_EOL;
}
private function test2(){
echo "test2", PHP_EOL;
}
protected function test3(){
return "test3" . PHP_EOL;
}
public function __call($method,$arguments) {
if(method_exists($this, $method)) {
$this->test1();
return call_user_func_array(array($this,$method),$arguments);
}
}
}
$a = new test;
$a->test2();
echo $a->test3();
/*
* Output:
* In test1
* test2
* In test1
* test3
*/
Please notice that test2 and test3 are not visible in the context where they are called due to protected and private. If the methods are public the above example will fail.
test1 does not have to be declared private.
ideone.com example can be found here
Updated: Add link to ideone, add example with return value.
All previous attempts are basically flawed because of http://ocramius.github.io/presentations/proxy-pattern-in-php/#/71
Here's the simple example, taken from my slides:
class BankAccount { /* ... */ }
And here's our "poor" interceptor logic:
class PoorProxy {
public function __construct($wrapped) {
$this->wrapped = $wrapped;
}
public function __call($method, $args) {
return call_user_func_array(
$this->wrapped,
$args
);
}
}
Now if we have the following method to be called:
function pay(BankAccount $account) { /* ... */ }
Then this won't work:
$account = new PoorProxy(new BankAccount());
pay($account); // KABOOM!
This applies to all solutions that suggest implementing a "proxy".
Solutions suggesting explicit usage of other methods that then call your internal API are flawed, because they force you to change your public API to change an internal behavior, and they reduce type safety.
The solution provided by Kristoffer doesn't account for public methods, which is also a problem, as you can't rewrite your API to make it all private or protected.
Here is a solution that does solve this problem partially:
class BankAccountProxy extends BankAccount {
public function __construct($wrapped) {
$this->wrapped = $wrapped;
}
public function doThings() { // inherited public method
$this->doOtherThingsOnMethodCall();
return $this->wrapped->doThings();
}
private function doOtherThingsOnMethodCall() { /**/ }
}
Here is how you use it:
$account = new BankAccountProxy(new BankAccount());
pay($account); // WORKS!
This is a type-safe, clean solution, but it involves a lot of coding, so please take it only as an example.
Writing this boilerplate code is NOT fun, so you may want to use different approaches.
To give you an idea of how complicated this category of problems is, I can just tell you that I wrote an entire library to solve them, and some smarter, wiser, older people even went and invented an entirely different paradigm, called "Aspect Oriented Programming" (AOP).
Therefore I suggest you to look into these 3 solutions that I think may be able to solve your problem in a much cleaner way:
Use ProxyManager's "access interceptor", which is basically a proxy type that allows you to run a closure when other methods are called (example). Here is an example on how to proxy ALL calls to an $object's public API:
use ProxyManager\Factory\AccessInterceptorValueHolderFactory;
function build_wrapper($object, callable $callOnMethod) {
return (new AccessInterceptorValueHolderFactory)
->createProxy(
$object,
array_map(
function () use ($callOnMethod) {
return $callOnMethod;
},
(new ReflectionClass($object))
->getMethods(ReflectionMethod::IS_PUBLIC)
)
);
}
then just use build_wrapper as you like.
Use GO-AOP-PHP, which is an actual AOP library, completely written in PHP, but will apply this sort of logic to ALL instances of classes for which you define point cuts. This may or may not be what you want, and if your $callOnMethod should be applied only for particular instances, then AOP is not what you are looking for.
Use the PHP AOP Extension, which I don't believe to be a good solution, mainly because GO-AOP-PHP solves this problem in a more elegant/debuggable way, and because extensions in PHP are inherently a mess (that is to be attributed to PHP internals, not to the extension developers).
Additionally, by using an extension, you are making your application as un-portable as possible (try convincing a sysadmin to install a compiled version of PHP, if you dare), and you can't use your app on cool new engines such as HHVM.
Maybe it is a little bit outdated but here come my 2 cents...
I don't think that giving access to private methods via __call() is a good idea. If you have a method that you really don't want to be called outside of your object you have no way to avoid it happening.
I think that one more elegant solution should be creating some kind of universal proxy/decorator and using __call() inside it. Let me show how:
class Proxy
{
private $proxifiedClass;
function __construct($proxifiedClass)
{
$this->proxifiedClass = $proxifiedClass;
}
public function __call($methodName, $arguments)
{
if (is_callable(
array($this->proxifiedClass, $methodName)))
{
doSomethingBeforeCall();
call_user_func(array($this->proxifiedClass, $methodName), $arguments);
doSomethingAfterCall();
}
else
{
$class = get_class($this->proxifiedClass);
throw new \BadMethodCallException("No callable method $methodName at $class class");
}
}
private function doSomethingBeforeCall()
{
echo 'Before call';
//code here
}
private function doSomethingAfterCall()
{
echo 'After call';
//code here
}
}
Now a simply test class:
class Test
{
public function methodOne()
{
echo 'Method one';
}
public function methodTwo()
{
echo 'Method two';
}
private function methodThree()
{
echo 'Method three';
}
}
And all you need to do now is:
$obj = new Proxy(new Test());
$obj->methodOne();
$obj->methodTwo();
$obj->methodThree(); // This will fail, methodThree is private
Advantages:
1)You just need one proxy class and it will work with all your objects.
2)You won't disrespect accessibility rules.
3)You don't need to change the proxified objects.
Disadvantage: You will lose the inferface/contract after wrapping the original object. If you use Type hinting with frequence maybe it is a problem.
Perhaps the best way so far is to create your own method caller and wrap around whatever you need before and after the method:
class MyClass {
public function callMethod()
{
$args = func_get_args();
if (count($args) == 0) {
echo __FUNCTION__ . ': No method specified!' . PHP_EOL . PHP_EOL;;
} else {
$method = array_shift($args); // first argument is the method name and we won't need to pass it further
if (method_exists($this, $method)) {
echo __FUNCTION__ . ': I will execute this line and then call ' . __CLASS__ . '->' . $method . '()' . PHP_EOL;
call_user_func_array([$this, $method], $args);
echo __FUNCTION__ . ": I'm done with " . __CLASS__ . '->' . $method . '() and now I execute this line ' . PHP_EOL . PHP_EOL;
} else
echo __FUNCTION__ . ': Method ' . __CLASS__ . '->' . $method . '() does not exist' . PHP_EOL . PHP_EOL;
}
}
public function functionAA()
{
echo __FUNCTION__ . ": I've been called" . PHP_EOL;
}
public function functionBB($a, $b, $c)
{
echo __FUNCTION__ . ": I've been called with these arguments (" . $a . ', ' . $b . ', ' . $c . ')' . PHP_EOL;
}
}
$myClass = new MyClass();
$myClass->callMethod('functionAA');
$myClass->callMethod('functionBB', 1, 2, 3);
$myClass->callMethod('functionCC');
$myClass->callMethod();
And here's the output:
callMethod: I will execute this line and then call MyClass->functionAA()
functionAA: I've been called
callMethod: I'm done with MyClass->functionAA() and now I execute this line
callMethod: I will execute this line and then call MyClass->functionBB()
functionBB: I've been called with these arguments (1, 2, 3)
callMethod: I'm done with MyClass->functionBB() and now I execute this line
callMethod: Method MyClass->functionCC() does not exist
callMethod: No method specified!
You can even go further and create a whitelist of methods but I leave it like this for the sake of a more simple example.
You will no longer be forced to make the methods private and use them via __call().
I'm assuming that there might be situations where you will want to call the methods without the wrapper or you would like your IDE to still autocomplete the methods which will most probably not happen if you declare the methods as private.
<?php
class test
{
public function __call($name, $arguments)
{
$this->test1(); // Call from here
return call_user_func_array(array($this, $name), $arguments);
}
// methods here...
}
?>
Try adding this method overriding in the class...
If you are really, really brave, you can make it with runkit extension. (http://www.php.net/manual/en/book.runkit.php). You can play with runkit_method_redefine (you can need Reflection also to retrieve method definition) or maybe combination runkit_method_rename (old function) / runkit_method_add (new function which wraps calls to your test1 function and an old function )
The only way to do this is using the magic __call. You need to make all methods private so they are not accessable from the outside. Then define the __call method to handle the method calls. In __call you then can execute whatever function you want before calling the function that was intentionally called.
Lets have a go at this one :
class test
{
function __construct()
{
}
private function test1()
{
echo "In test1";
}
private function test2()
{
echo "test2";
}
private function test3()
{
echo "test3";
}
function CallMethodsAfterOne($methods = array())
{
//Calls the private method internally
foreach($methods as $method => $arguments)
{
$this->test1();
$arguments = $arguments ? $arguments : array(); //Check
call_user_func_array(array($this,$method),$arguments);
}
}
}
$test = new test;
$test->CallMethodsAfterOne('test2','test3','test4' => array('first_param'));
Thats what I would do

PHP dynamic class extending

I know you can extend a class when constructing it like the following:
class b extends a {
}
But is it possible to dynamically extend classes from the scripts? Such as:
$b = new b($input) extends a;
What I wish to accomplish is to extend the module differnetly wheither it's used in admin rather than the public pages. I know I can create two different parent classes by the same name and only include one per admin or public. But my question is, is it possible to do it dynamically in PHP?
No, not without an extension like RunKit.
You might consider an alternative approach. If you want B to assume the functionality of A, perhaps something like the following could provide a sort of "mixin" approach. The general picture is that, instead of B being a child of A, B delegates to A.
<?php
class MixMeIn
{
public $favouriteNumber = 7;
public function sayHi() {
echo "Hello\n";
}
}
class BoringClass
{
private $mixins = array();
public function mixin($object)
{
$this->mixins[] = $object;
}
public function doNothing() {
echo "Zzz\n";
}
public function __call($method, $args)
{
foreach ($this->mixins as $mixin)
{
if (method_exists($mixin, $method))
{
return call_user_func_array(array($mixin, $method), $args);
}
}
throw new Exception(__CLASS__ + " has no method " + $method);
}
public function __get($attr)
{
foreach ($this->mixins as $mixin)
{
if (property_exists($mixin, $attr))
{
return $mixin->$attr;
}
}
throw new Exception(__CLASS__ + " has no property " + $attr);
}
public function __set($attr, $value)
{
foreach ($this->mixins as $mixin)
{
if (property_exists($mixin, $attr))
{
return $mixin->$attr = $value;
}
}
throw new Exception(__CLASS__ + " has no property " + $attr);
}
}
// testing
$boring = new BoringClass();
$boring->doNothing();
try {
$boring->sayHi(); // not available :-(
}
catch (Exception $e) {
echo "sayHi didn't work: ", $e->getMessage(), "\n";
}
// now we mixin the fun stuff!
$boring->mixin(new MixMeIn());
$boring->sayHi(); // works! :-)
echo $boring->favouriteNumber;
Just a zany idea. I hope I understood the question correctly.
You can't, but this has been requested for a few years: https://bugs.php.net/bug.php?id=41856&edit=1
You can define the classes within an eval, but it's more trouble than declaring the class normally.
But you cannot use extends while object creation. extends is used in class definition only and defines which other class is "parent" for our new class.
Alternatively, if you are comfortable with javascript-style inheritance and don't mind losing typechecking:
<? //PHP 5.4+
final class ExpandoLookalike {
//Allow callable properties to be executed
public function __call($name, $arguments) {
\call_user_func_array($this->$name, $arguments);
}
}
$newBaseModule = static function(){
$base = new ExpandoLookalike();
//Common base functions get assigned here.
$basePrivateVar = 42;
$base->commonFunction = static function($params1, $params2) use ($basePrivateVar){
echo "common function\n";
};
$base->comment = static function() use ($basePrivateVar){
echo "Doing base comment with $basePrivateVar\n";
};
return $base;
};
//Javascript-style extends
$newAdminModule = static function($param) use ($newBaseModule){
$base = $newBaseModule();
$privateVar = 5;
$base->adminProperty = 60;
$base->suspendSite = static function() use ($param, $privateVar){
echo 'Doing admin only function ';
echo "with $param, $privateVar\n";
};
return $base;
};
$newPublicModule = static function() use ($newBaseModule){
$base = $newBaseModule();
$privateVar = 3;
//Javascript-style overloading
$oldComment = $base->comment;
$base->comment = static function($data) use ($oldComment, $privateVar){
$oldComment();
echo 'Doing public function ';
echo "with $data\n";
};
return $base;
};
$baseModule = $newBaseModule();
$adminModule = $newAdminModule('P');
$publicModule = $newPublicModule();
$adminModule->suspendSite(); //echos 'Doing admin only function with P, 5'
echo "{$adminModule->adminProperty}\n"; //echos '60'
$publicModule->comment('com'); //echos 'Doing base comment with 42'
//'Doing public function with com'
?>
Despite closing the door to traits and interfaces, it opens up other interesting doors to compensate:
<? //PHP 5.4+
$inheritAllTheThings = static function(){
$base = new ExpandoLookalike();
foreach(\func_get_args() as $object){
foreach($object as $key => $value){
//Properties from later objects overwrite properties from earlier ones.
$base->$key = $value;
}
}
return $base;
};
$allOfEm = $inheritAllTheThings(
$newPublicModule(),
$newAdminModule('Q'),
['anotherProp' => 69,]
);
$allOfEm->comment('f'); //echos 'Doing base comment with 42'
//Because AdminModule came after PublicModule, the function that echos 'f'
//from PublicModule was overridden by the function from AdminModule.
//Hence, order denotes resolutions for multiple inheritance collisions.
$allOfEm->suspendSite(); //echos 'Doing admin only function with Q, 5'
echo $allOfEm->anotherProp . "\n"; //echos '69'
?>
You can with typecasting. If a extends b then you could do
$a=(a)(new b($input));
Which isn't exactly the same, but similar.
You can look: https://github.com/ptrofimov/jslikeobject
Author implemented JS-like objects with support of inheritance.
But perhaps it is not so good to use such objects instead of usual ones.
Yes, as cory mentioned, this feature has been requested before. But before that, you can create a workaround. Here is my old school trick for this
Create two separate classes like these:
class a {
}
class b {
public $object;
}
Then, create an extended version too
class bextendeda extends a {
}
In the constructor method of class b, place few functions which redirects to the extended object if requested.
class b {
public $object;
public function __contruct($extend = false) {
if($extend) $this -> object = new bextendeda();
else $this -> object = $this;
}
function __get($prop) {
return $this-> object -> $prop;
}
function __set($prop, $val) {
$this-> object -> $prop = $val;
}
function __call($name, $arguments)
{
return call_user_func_array(array($this -> object, $name), $arguments);
}
}
And there you have it, IF you want the extended version just do this
$b = new b(true);
If not
$b = new b();
Enjoy :)

PHP: Chaining Method Calls [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
PHP method chaining?
I occasionally see some php applications use classes like that:
$Obj = new Obj();
$Obj->selectFile('datafile.ext')->getDATA();
The example above gets the contents of the selected file then returns them ( just an example );
Well, before i decided to ask you how can I do this, I tried this:
class Someclass {
public function selectFile( $filename ) {
$callAclass = new AnotherClass( $filename );
return $callAclass;
}
// Other functions ...
}
class AnotherClass {
protected $file_name;
public function __construct ( $filename ) { $this->file_name = $filename; }
public function getDATA ( ) {
$data = file_get_contents( $this->file_name );
return $data;
}
// funcs , funcs, funcs ....
}
Is that the right way to accomplish this task? And please tell me what these classes are called.
It's called method chaining. Have a look at this question on SO.
Here's a way you can do what you're trying to achieve:
class File
{
protected $_fileName;
public function selectFile($filename)
{
$this->_fileName = $filename;
return $this;
}
public function getData()
{
return file_get_contents($this->_fileName);
}
}
$file = new File();
echo $file->selectFile('hello.txt')->getData();
Notice we return $this in the selectFile, this enables us to chain another method onto it.
The above example (the first one) is something called chaining. Here's a regular class:
class a_class
{
public function method_a()
{
echo 'method a';
}
public function method_b()
{
echo ' - method b';
}
}
You'd call those like this:
$class = new a_class();
$class->method_a();
$class->method_b();
Which would echo 'method a - method b'. Now to chain them, you'd return the object in the methods:
class a_class
{
public function method_a()
{
echo 'method a';
return $this;
}
public function method_b()
{
echo ' - method b';
return $this;
}
}
You'd call those like this:
$class = new a_class();
$class->method_a()->method_b();
Which would also echo 'method a - method b'.
Although I have returned the object in the last method - you strictly wouldn't need to, only the preceding methods require that for chaining.

Is it possible to use mixins in php

I came to know about mixins.So my doubt is, is it possible to use mixins in php?If yes then how?
Use Trait introduced in PHP 5.4
<?php
class Base {
public function sayHello() {
echo 'Hello ';
}
}
trait SayWorld {
public function sayHello() {
parent::sayHello();
echo 'World!';
}
}
class MyHelloWorld extends Base {
use SayWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
?>
which prints Hello World!
http://php.net/manual/en/language.oop5.traits.php
This answer is obsolete as of PHP 5.4. See Jeanno's answer for how to use traits.
It really depends on what level of mixins you want from PHP. PHP handles single-inheritance, and abstract classes, which can get you most of the way.
Of course the best part of mixins is that they're interchangeable snippets added to whatever class needs them.
To get around the multiple inheritance issue, you could use include to pull in snippets of code. You'll likely have to dump in some boilerplate code to get it to work properly in some cases, but it would certainly help towards keeping your programs DRY.
Example:
class Foo
{
public function bar( $baz )
{
include('mixins/bar');
return $result;
}
}
class Fizz
{
public function bar( $baz )
{
include('mixins/bar');
return $result;
}
}
It's not as direct as being able to define a class as class Foo mixin Bar, but it should get you most of the way there. There are some drawbacks: you need to keep the same parameter names and return variable names, you'll need to pass other data that relies on context such as func_get_args_array or __FILE__.
Mixins for PHP (PHP does not implement Mixins natively, but this library will help)
First google result for "php5 mixin": http://www.sitepoint.com/forums/php-application-design-147/ruby-like-mixins-php5-332491.html
First google result for "php mixin": http://www.advogato.org/article/470.html
Short answer: yes, but not natively (yet, evidently, as #mchl notes). Check those out.
Longer answer: if you're using runkit, checkout runkit_method_copy(): "Copies a method from class to another."
I based mixins functionality on the blog entry found at jansch.nl.
class Node
{
protected $__decorator_lookup = array();
public function __construct($classes = array())
{
foreach($classes as $class)
if (class_exists($class))
{
$decorator = new $class($this);
$methods = get_class_methods($decorator);
if (is_array($methods))
foreach($methods as $method)
$this->__decorator_lookup[strtolower($method)] = $decorator;
}
else
trigger_error("Tried to inherit non-existant class", E_USER_ERROR);
}
public function __get($name)
{
switch($name)
{
default:
if ($this->__decorator_lookup[strtolower($name)])
return $this->__call($name);
}
}
public function __call($method, $args = array())
{
if(isset($this->__decorator_lookup[strtolower($method)]))
return call_user_func_array(array($this->__decorator_lookup[strtolower($method)], $method), $args);
else
trigger_error("Call to undefined method " . get_class($this) . "::$method()", E_USER_ERROR);
}
public function __clone()
{
$temp = $this->decorators;
$this->decorators = array();
foreach($temp as $decorator)
{
$new = clone($decorator);
$new->__self = $this;
$this->decorators[] = $new;
}
}
}
class Decorator
{
public $__self;
public function __construct($__self)
{
$this->__self = $__self;
}
public function &__get($key)
{
return $this->__self->$key;
}
public function __call($method, $arguments)
{
return call_user_func_array(array($this->__self, $method), $arguments);
}
public function __set($key, $value)
{
$this->__self->$key = $value;
}
}
class Pretty extends Decorator
{
public function A()
{
echo "a";
}
public function B()
{
$this->b = "b";
}
}
$a = new Node(array("Pretty"));
$a->A(); // outputs "a"
$a->B();
echo($a->b); // outputs "b"
EDIT:
As PHP clone is shallow, added __clone support.
Also, bear in mind that unset WON'T work (or at least I've not managed to make it work) within the mixin. So - doing something like unset($this->__self->someValue); won't unset the value on Node. Don't know why, as in theory it should work. Funny enough unset($this->__self->someValue); var_dump(isset($this->__self->someValue)); will produce correctly false, however accessing the value from Node scope (as Node->someValue) will still produce true. There's some strange voodoo there.

Categories