Re: [Reflection] Improve logic of ReflectionMethod->invokeArgs() for static methods

From: Date: Mon, 14 Jan 2013 20:15:53 +0000
Subject: Re: [Reflection] Improve logic of ReflectionMethod->invokeArgs() for static methods
References: 1 2 3 4  Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message
Probably, it will be better to give a link to the one of examples of
AOP integration for laravel framework (requires 5.4.10 to work):
https://github.com/lisachenko/laravel-aspect
(just clone, install
dependencies and look at result)

I need to perform weaving of aspects into the original methods, so
here is an example of generated source code:

<?php namespace Illuminate\Foundation;

class AliasLoader__AopProxied {

        // .. source code here

	/**
	 * Get or create the singleton alias loader instance.
	 *
	 * @param  array  $aliases
	 * @return Illuminate\Foundation\AliasLoader
	 */
	public static function getInstance(array $aliases = array())
	{
		if (is_null(static::$instance)) static::$instance = new static($aliases);
		
		$aliases = array_merge(static::$instance->getAliases(), $aliases);

		static::$instance->setAliases($aliases);

		return static::$instance;
	}

	/**
	 * Load a class alias if it is registered.
	 *
	 * @param  string  $alias
	 * @return void
	 */
	public function load($alias)
	{
		if (isset($this->aliases[$alias]))
		{
			return class_alias($this->aliases[$alias], $alias);
		}
	}

        // more source code here
}

class AliasLoader extends AliasLoader__AopProxied
{
    /**
     *Property was created automatically, do not change it manually
     */
    private static $__joinPoints = array();

    // some source code here

    /**
     * Get or create the singleton alias loader instance.
     *
     * @param  array  $aliases
     * @return Illuminate\Foundation\AliasLoader
     */
    public static function getInstance(array $aliases = array())
    {
        return self::$__joinPoints['static:getInstance']->__invoke(get_called_class(),
array($aliases));
    }

    /**
     * Load a class alias if it is registered.
     *
     * @param  string  $alias
     * @return void
     */
    public function load($alias)
    {
        return self::$__joinPoints['method:load']->__invoke($this,
array($alias));
    }

    // some source code here
}

You can notice, that original class name is pointing to the decorator
class after weaving. Source code still use $class = new AliasLoader(),
but the class now contains additional logic that was introduced by
aspects.

2013/1/14 Sebastian Krebs <[email protected]>:
>
>
>
> 2013/1/14 Alexander Lissachenko <[email protected]>
>>
>> My use-case is weaving aspects into the methods. Yeah! )
>>
>> So, I take the original class, rename it and then create a decorator
>> class instead of original class with overridden dynamic and static
>> methods. Method in the decorator should make some specific logic and
>> then just invokes the original static method with Reflection, but the
>> scope should be also correct.
>>
>> For example, previous class First will be renamed during load-time to
>> the First_AopProxied:
>>
>> class First_AopProxied
>> {
>>     public static function foo()
>>     {
>>         echo get_called_class();
>>     }
>> }
>>
>> and decorator will be created
>>
>> class First extends First_AopProxied
>> {
>>     public static function foo()
>>     {
>>         // some logic here, that should call parent method and
>> preserve the scope (class First)
>>         // can not use parent::foo() here, because around advice
>> should be able to call this method somewhere in the closure...
>>     }
>> }
>
>
> I must say this example is not really better than the last one (it feels
> like it is exactly the same with 2 lines more comments). Also I don't know,
> what you mean by "call this method somewhere in the closure"; which
> closure?!?
> I guess you are in fact looking for regular instance methods.
>
>>
>>
>> 2013/1/14 Sebastian Krebs <[email protected]>:
>> >
>> >
>> >
>> > 2013/1/14 Alexander Lissachenko <[email protected]>
>> >>
>> >> Hi! It's my first letter here )
>> >>
>> >> I want to suggest a small improvement for ReflectionMethod->invoke()
>> >> and ReflectionMethod->invokeArgs() methods to support LSB for
>> >> overridden static methods. Currently, for invoking static methods
>> >> first argument should be null, information about class (scope) is
>> >> taken from the reflection class. However, there is one issue that can
>> >> not be solved at the current time.
>> >>
>> >> Suppose, we have two classes:
>> >>
>> >> class First
>> >> {
>> >>     public static function foo()
>> >>     {
>> >>         echo get_called_class();
>> >>     }
>> >> }
>> >>
>> >> class Second extends First
>> >> {
>> >>     public static function foo()
>> >>     {
>> >>         echo "Do not call me, please";
>> >>     }
>> >> }
>> >>
>> >> Now I want to invoke the First::foo() method with Reflection from the
>> >> Second class scope for using LSB. Currently this is impossible:
>> >> $class = new ReflectionClass('First');
>> >> $class->getMethod('foo')->invokeArgs(null, array()); // Outputs
>> >> 'First' as no scope information is passed
>> >>
>> >>
>> >> $class = new ReflectionClass('Second');
>> >> $class->getMethod('foo')->invokeArgs(null, array()); // Outputs
>> >> 'Do
>> >> not call me, please' as method is redefined
>> >>
>> >> So, there is no way now to invoke the static First::foo() method from
>> >> the child scope because it was redefined. However, this can be easily
>> >> implemented by adding the scope for static methods invocation (like
>> >> Closure::bindTo()):
>> >>
>> >> $class = new ReflectionClass('First');
>> >> $class->getMethod('foo')->invokeArgs('Second', array());
>> >> // Outputs
>> >> 'Second'
>> >>
>> >> This improvement can be very useful for building proxies for static
>> >> methods, that use LSB. Can it be implemented for PHP 5.3-5.5? Thanks!
>> >
>> >
>> > Maybe it's just me, but could you explain which use-case want to solve?
>> > The
>> > example isn't very useful, because you can achieve this quite easy
>> > without
>> > reflection. Also why do you override the method, when you don't want it
>> > to
>> > get called? Shouldn't they two separate methods then?
>> >
>> > <?php
>> > class First
>> > {
>> >     public static function foo()
>> >     {
>> >         echo get_called_class();
>> >     }
>> > }
>> >
>> > class Second extends First
>> > {
>> >     public static function foo()
>> >     {
>> >         echo "Do not call me, please";
>> >     }
>> > public static function bar() {
>> > parent::foo();
>> > }
>> > }
>> > Second::bar();
>> >
>> > http://codepad.viper-7.com/fwG5GB
>> >
>> >>
>> >>
>> >> --
>> >> PHP Internals - PHP Runtime Development Mailing List
>> >> To unsubscribe, visit: http://www.php.net/unsub.php
>> >>
>> >
>> >
>> >
>> > --
>> > github.com/KingCrunch
>
>
>
>
> --
> github.com/KingCrunch


Thread (8 messages)

« previous php.internals (#64949) next »