Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NFR] Events & Weak References #658

Closed
igorgolovanov opened this issue May 21, 2013 · 12 comments
Closed

[NFR] Events & Weak References #658

igorgolovanov opened this issue May 21, 2013 · 12 comments

Comments

@igorgolovanov
Copy link
Contributor

Weak references provide a non-intrusive gateway to ephemeral objects. Unlike normal (strong) references, weak references do not prevent the garbage collector from freeing that object. For this reason, an object may be destroyed even though a weak reference to that object still exists. In such conditions, the weak reference seamlessly becomes invalid.

I suggest to use Weak References with Events (with Listeners).

Base idea:

class MyListener
{
    public function afterQuery()
    {
        echo 'Running afterQuery';
    }
}

$eventsManager = new Phalcon\Events\Manager();
$myListener = new MyListener();
$eventManager->attachUsingWeakRef('somecomponent', $myListener);

$eventsManager->fire('somecomponent:afterQuery', null); 
// this shows "Running afterQuery"

unset($myListener); 
// after this step, myListener doesn't have any references anymore and it must die.

$eventsManager->fire('somecomponent:afterQuery', null); 
// nothing happens, because myListener has died.

I have three suggests (must be selected only one):

1.Always uses WeakRef for all event-handlers

p.s. But i don't like this solution, because we need strong references in some cases.

$eventsManager = new Phalcon\Events\Manager();
$myListener = new MyListener();
$eventManager->attach('somecomponent', $myListener); 
// always use WeakRef for all event handlers.
// can't be uses with strong references
2.Add a flag/method for use or not weak references.
$eventsManager = new Phalcon\Events\Manager();
$myListener = new MyListener();

// flag
$eventManager->attach('somecomponent', $myListener, $priority, $isWeak);
// method
$eventManager->attachUsingWeakRef('somecomponent', $myListener, $priority);
3.Use weakref-php-extension and add possibility register Event-handler as "WeakRef" object.

So when event fired then will checked that event-handler is WeakRef object or not.
If is WeakRef object then will check whether the object referenced still exists and if exists - fire!
If is not WeakRef object then standart fire.

$eventsManager = new Phalcon\Events\Manager();
$myListener = new MyListener();

$eventManager->attach('somecomponent', new WeakRef($myListener));

Avaliable php-extension for Weak References: http://www.php.net/manual/en/book.weakref.php


Zend Framework 2 uses WeakRef extension.

@iforp
Copy link
Contributor

iforp commented May 21, 2013

  1. You unlinked $myListener variable of MyListener object, but $eventsManager still keeps this reference

@iforp
Copy link
Contributor

iforp commented May 21, 2013

Garbage collector copes poorly with only cyclical references:

class A
{
    public $b;
}

class B {
    public $a;
}

$a = new A;
$b = new B;
$a->b = $b;
$b->a = $a;

unset($a, $b); // memory still leaks

But you may always call gc_collect_cycles()

@igorgolovanov
Copy link
Contributor Author

I know how GC working. gc_collect_cycles() - it's other.

1) You unlinked $myListener variable of MyListener object, but $eventsManager still keeps this reference

In first way i suggest always use WeakRef in Event\Manager without strong references. So in this case after unset($myListener) Event\Manager must always lose references to $myListener.

@iforp
Copy link
Contributor

iforp commented May 22, 2013

What will happen with $myListener if it was initialized inside some method after it is executed?

call_user_func(function() use($di)
{
    $myListener = new MyListener();
    $di->get('eventsManager')->attachUsingWeakRef('somecomponent', $myListener);
});

Should the GC deallocate $myListener?

@igorgolovanov
Copy link
Contributor Author

@Agent-J In this case - yes. Because after your Closure will be executed the $myListener will not have any strong references anymore. And all event-handlers provided by this listener will be "unatached" from EventsManager.

@iforp
Copy link
Contributor

iforp commented May 22, 2013

So you will be able to attach the listener only in the global scope or ongoing call stack otherwise the reference will be lost.

@iforp
Copy link
Contributor

iforp commented May 22, 2013

And what about this case?

$eventsManager->attachUsingWeakRef('somecomponent', new MyListener());

@igorgolovanov
Copy link
Contributor Author

I sent a simple pull. You can try how it works :)

@sasezaki
Copy link

@golovanov

Zend Framework 2 uses WeakRef extension.

No! nowadays, no!
zendframework/zendframework#4373
weierophinney/zendframework@b7e2abf

@igorgolovanov
Copy link
Contributor Author

@sasezaki You're right! To this point has already been removed this functionality from zend, because there it used by default. So when weakref was installed or wasn't installed, this was causing the different behavior of logic of zf2. I not suggest using by default, i suggest add a possibility to use weakref. And who don't know how it works will not use this, but who know how it works can use this (and will able to achieve an increase in productivity and a significant reduction in memory usage)

@phalcon
Copy link
Collaborator

phalcon commented Oct 2, 2013

Implemented in 1.3.0

@phalcon phalcon closed this as completed Oct 2, 2013
@igorgolovanov
Copy link
Contributor Author

Coool! Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants