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
[WIP] Significant reduction in memory consumption #1426
Conversation
@qiangxue What do you think about this catch? :) |
It's a good catch, but the fix has the drawback that it makes the methods implicit and thus the corresponding API doc is gone. Instead of using this fix, one can work around the issue by overriding the |
@qiangxue Yes you right. But behavior developer need to think always about |
@qiangxue Another approach here. Without drawbacks (i think). |
Seems my solution have side effects with behaviors child classes. I think we need add note about override |
BC break? I don't think we want it. Still reducing memory consumption is a very good thing. |
public function attach($owner)
{
$this->_owner=$owner;
if(($events=$this->events())!==array()){
$reflector=new ReflectionClass($this);
foreach($events as $event=>$handler){
$methodClass=$reflector->getMethod($handler)->class;
if($methodClass!=='CModelBehavior'&&$methodClass!=='CActiveRecordBehavior')
$owner->attachEventHandler($event,array($this,$handler));
}
}
} BC don't break and work with children classes. |
@slavcodev It will not work for custom components extended from |
I think we can go with blank methods removal. It's BC. Problem with IDEs completion can be solved via some additional PHPDoc. Documentation from methods can be moved to class header. |
I think what @slavcodev suggested is a good compromise. The memory issue is important mainly when there are many instances of the same component class. This mainly happens to ActiveRecord. I'm against removing the methods. Although we can put the needed doc into the class header, it's not neat. More importantly, we don't have class header inheritance (i.e. methods defined in the parent class won't have their doc showing in the child class header, if we choose to remove the methods.) |
@qiangxue so you think fixing it for two specific classes is enough? |
I don't think it's a good idea to hadcode class names too. I vote for method_exists() + move doc to header. Why:
|
@samdark It's enough for most cases. This problem mainly happens to base classes. It's not common that people will develop new base behavior classes. If they do, they can use the class_exists() approach to avoid the memory issue. |
I insist on the fact that the fix should be the same as in the last commit. Without fix With fix
|
What about the performance result of what @slavcodev suggested? And how did you do the test? |
Time: 0.64722 s |
Then I vote for @slavcodev's approach. |
@qiangxue I have more interesting idea. Will show shortly. |
@qiangxue I think we have ideal solution in last commit: Time: 0.80 s There is no hardcoded classes. |
Yes, this is better. Could you please double check to make sure it works with PHP 5.1? |
One potential problem is that someone defines an abstract behavior class with non-empty methods which contain default implementation. |
@qiangxue Can we ignore this potential problem? Or we need other solution? |
@creocoder am, i got this one problem that @qiangxue discribed. I mean i have component which has defaults 3 behaviors, that has some defaults method, so i will get en error here?am i right? |
@Ragazzo This behaviors is abstract? |
@creocoder in on use-case yes(other behaviors in modules just overrides him - this one is abstract), and some other not, i've described them above, they just extending CBehavior. I think that your solution for memory consumption is good, can u then just describe how to fix this problem, if your solution will be accepted. |
:-) No man. You just will see |
All right, fine. |
Maybe a bit late, but I agree with @klimov-paul - changing method visibility from protected to public is not obvious and in my opinion it is a bad OOP practice. And Yii is a very good example of strong and correct OOP approach. So I think that solution suggested by @slavcodev is better and fix issue for existing Yii classes. |
Yii is whatever, but NOT a good OOP approach. It violates MVC principles and forces dependencies in so many places that I don't eve want to list them. Learn OOP and take it easy. Yii is what it is, and it is an OOP with a strong smell of spaghetti-joomla. |
@grikdotnet I can NOT imagine worse place then github issue to post your opinion about what Yii is. |
It is not bad practice in our case. Imagine that we hit in 1% of situations when changing method visibility is good and best choose we can do.
Hardcoding childen classes in parent class is worst thing we can do from OOP point of view.
This is not DRY. P.S. I hope you will understand our decision when to weigh the pros and cons. |
@creocoder I agree that current solution looks eleagant comparing to all other variants, but it is sill not perfect. |
@apptous-seb Visibility changing in children classes from strong to weak is not a hack. |
The solution breaks a BC!
I am not sure why such thing happens. I am using Yii 1.1.12 at PHP 5.3.3. |
@klimov-paul you are first, this is what I was waiting for that option with protected/public confuses many. class TestModelBehavior extends CBehavior {
public function events() {
return array(
'onBeforeValidate' => 'beforeValidate'
);
}
public function beforeValidate() {
die(__METHOD__);
}
} |
Can't confirm. Anyway this solution not break BC. There is no places where:
|
@slavcodev , @creocoder The code by @klimov-paul works and this means that it is possible to use protected methods as event handlers. @klimov-paul I think protected methods work because event handeling is in CComponent and CBehavior extends CComponent, so CComponent is able to call protected method of CBehavior instance. |
@sebgoo Someone can already have another BUGS in app. Who cares about it? Event handlers should be PUBLIC. |
The example I have provided works at my server. The protected event handler is actually invoked! In my example "beforeValidate()" handles event, however
will produce an error. |
This solution will produce a silent (without any message) error in case there is a proteceted event handler. |
@klimov-paul Congratulations. You have not found anything better than to look for what is non-existent in practice code. |
Perhaps I did. |
@klimov-paul :-) You cant change public to protected in children. Your example is specially forged. TestModelBehavior will extends CModelBehavior in real applications! So stop spam this thread with garbage non-existent code. |
@klimov-paul By the way your example works only if we extend CBehavior, but will fail with error if we extend CModelBehavior (can not change public to protected), so it is a very small chance to break someone's code. |
Another idea - detect empty event handlers based on method length: public function attach($owner)
{
$this->_owner=$owner;
if(($events=$this->events())!==array()){
$reflector=new ReflectionClass($this);
foreach($events as $event=>$handler){
$method=$reflector->getMethod($handler);
$length=$method->getEndLine() - $method->getStartLine();
if($length)
$owner->attachEventHandler($event,array($this,$handler));
}
}
}
...
/**
* PHP docs
*/
public function afterConstruct($event) {} The only drawback I see is code formatting - we need to define empty handlers in single line to get zero length. |
@sebgoo You really think this solution is better??? More unreliable and ugly solution hard to think.. |
@creocoder Just another option, don't be so angry ))) and, by the way, thanks for your efforts - you do a great job by finding and trying to fix such issues as this and I am not trying to reject it. |
I see that this may cause problems with existing code in some rare cases. I think solution is good as it is but we should mention this change in UPGRADE notes. created an issue for that: #1550 |
With this fix:
Without: