I extensively use a "view/subview" approach, where a controller renders a viewA as in:
//controller/action code
$this->render("viewA");
and then this view renders another sub-view a lot of times in a loop (e.g. to display several messages, i.e.:
//in viewA.php
//...
for (/* many dozens times */) {
$this->renderPartial("_viewB",$someData);
}
And the nesting may go on. i.e. _viewB may in turn do a renderPartial() of another subview...
Now, this seemed to me the most natural thing in the world, but then I found out it has a tremendous overhead.
At first i thought the overhead came from resolving the views, so I already reduced that by calling renderInternal() instead of renderPartial() and passing it the (almost) hard-coded path of the view file. The improvement was small.
So I even tried replacing renderPartial() with require() (taking care of avoiding variable conflicts) and the improvement was almost null, as expected (i.e. the only thing renderPartial() does besides a require() is an expand() and that is negligible).
Then I tried by embedding the subviews into the outer view, that is, copying all the code into only one view, so that I have no require() at all.
To my surprise, the impact on performance is HUGE: about 50 milliseconds of overhead (on about 100ms of actually rendering the output) when the loop repeats about 150 times.
I already have APC enabled, and I have set apc.stat=0, but that doesn't change a thing (which is weird). By monitoring APC I see as many hits as I expect, so the file apparently is being properly served from cache.
So, it seems that a require() is expensive in itself, even if apc is enabled.
However, I do need to keep the sub-views separate, because I use them in different "outer" views.
The only "trick" that comes to my mind, is to put the sub-view code into a function, in a file that is only included once; and then call that function instead of renderPartial()ing a subview. This is a bit ugly, though.
A similar trick would be to create a widget, but it seems kind of an overkill, and won't it be even more expensive?
Are there any other approches I am overlooking?
//controller/action code
$this->render("viewA");
and then this view renders another sub-view a lot of times in a loop (e.g. to display several messages, i.e.:
//in viewA.php
//...
for (/* many dozens times */) {
$this->renderPartial("_viewB",$someData);
}
And the nesting may go on. i.e. _viewB may in turn do a renderPartial() of another subview...
Now, this seemed to me the most natural thing in the world, but then I found out it has a tremendous overhead.
At first i thought the overhead came from resolving the views, so I already reduced that by calling renderInternal() instead of renderPartial() and passing it the (almost) hard-coded path of the view file. The improvement was small.
So I even tried replacing renderPartial() with require() (taking care of avoiding variable conflicts) and the improvement was almost null, as expected (i.e. the only thing renderPartial() does besides a require() is an expand() and that is negligible).
Then I tried by embedding the subviews into the outer view, that is, copying all the code into only one view, so that I have no require() at all.
To my surprise, the impact on performance is HUGE: about 50 milliseconds of overhead (on about 100ms of actually rendering the output) when the loop repeats about 150 times.
I already have APC enabled, and I have set apc.stat=0, but that doesn't change a thing (which is weird). By monitoring APC I see as many hits as I expect, so the file apparently is being properly served from cache.
So, it seems that a require() is expensive in itself, even if apc is enabled.
However, I do need to keep the sub-views separate, because I use them in different "outer" views.
The only "trick" that comes to my mind, is to put the sub-view code into a function, in a file that is only included once; and then call that function instead of renderPartial()ing a subview. This is a bit ugly, though.
A similar trick would be to create a widget, but it seems kind of an overkill, and won't it be even more expensive?
Are there any other approches I am overlooking?