views:

196

answers:

3

I've been using rails, merb, django and asp.net mvc applications in the past. What they have common (that is relevant to the question) is that they have code that sets up the framework. This usually means creating objects and state that is persisted until the web server is recycled (like setting up routing, or checking which controllers are available, etc).

As far as I know PHP is more like a CGI script that gets compiled to some bytecode each time it's run, and after the request it's discarded. Of course you can have sessions, to persist data between requests from the same user, and as I see there are extensions like APC, with which you can persist objects between requests at the server level.

My question is: how can one create a PHP application that works like rails and such? I mean an application that on the first requests sets up the framework, then on the 2nd and later requests use the objects that are already set up. Is there some built in caching facility in mod_php? (for example that stores the compiled bytecode of the executed php applications) Or is using APC or some similar extensions the only way to solve this problem? How would you do it?

Thanks.

EDIT: Alternative question: if I create a large PHP application that has a very large set up time, but minor running time (like in the frameworks mentioned above) then how should I "cache" the things that are already set up (this might mean a lot of things, except for maybe the database connections, because for that you have persistent connections in PHP already).

To justify large set up time: what if I'm using PHP reflection to check what objects are available and set the runtime according to that. Doing a lot of reflection is usually slow, but one has to do it only once (and re-evaluate only if the source code is modified).

EDIT2: It seems it's APC then. The fact that it caches bytecode automatically is good to know.

A: 

I think you're making some incorrect generalizations. All of those frameworks (ex: Rails) can be run with different configurations. Under some, a process is created for every request. This obviously hurts performance, but it shows that these frameworks don't rely on a long-running process. They can set things up (reparse config files, create objects, etc.) every request if needed.

Of course, mod_php (the way PHP is usually used) runs inside the web server process, unlike CGI. So I don't see anything fundamentally different between CakePHP (for example) and Rails.

I think perhaps you are looking for something like Python's WSGI or Ruby's Rack, but for PHP. This specifies an interface (independent of how the language is run) for an application. For a new request, a new instance of an application object is created. As far as I know, this does not exist for PHP.

Matthew Flaschen
Yes, but they are usually not discarded and regenerated after each request. Of course you can make rails work that way, but it will also mean you have 3-4 seconds of setup time each request. And for some even if there are new processes generated they share something from the set up framework.
SztupY
3-4 seconds of setup time is a bit of a grandiose exaggeration, standard rails requests take less than 100 miliseconds on my development machines (which means RoR is running in development which means it's parsing files each and every time). Edit: You possibly have a far more complex setup than what a standard framework has so this comment is defunct.
Matt S
Rails is usually run as a separate process for which the web server connects when it needs to serve another process. Passenger/mod_rails is used to handle these processes. AFAIK mod_php won't create a separate server application process (nor will it connect to it), it will just interpret the php file, and it's up to this php file to do what it needs to do. Looking at the CakePHP source codes it seems it has some caching support, but I don't know what it actually caches.
SztupY
@Matt S: rails won't reparse each file on development setup. It will only reparse modified files inside your rails application (meaning mainly the `app` directory). If you change some plugins, or even the main rails stuff (like `active_record`), it will only see the modifications after a complete recycle, which does take a lot of time. Of course during development one usually does not change the plugins or the core rails, so this isn't usually visible. And yes, loading up all the plugins and the core rails take the most time, not the actual serving of the requests.
SztupY
+1  A: 

PHP (and ruby for that matter) are interpretive languages. That is they parse the files each time they are requested and I suppose you could say are converted to a pseudo byte code. It is more 'apparent' one could say that PHP is more like this than say RoR but they both behave the same way.

The feature of persisting data between requests is a feature of the server not of the language itself. For example, the RoR routing you speak of is in fact cached but that's cached in the server's local memory. It isn't compiled and stored for faster readins. The server (and by server I mean both the box & the web service instances) restarts this information is gone. The 'setting up the framework' you speak of still involves parsing EACH file involved in the framework. Rails parses each file during the request again and again, the production level features may in fact cache this data in memory but certainly in development it does not. The only reason I mention that is because it illustrates that it's a feature of the server not the language.

To achieve the same thing in PHP you could use Zend Server. As far as I know this is the only PHP interpreter that will 'compile' and use byte code when told to. Otherwise you'll need to find a way to store the data you want to persist over requests. APC as you mentioned is a very powerful feature, a more distributed one is Memcached and then of course there's more persistent forms like disc & sql.

I am interested in knowing why you'd like this particular feature. Are you noticing performance issues that would be 'solved' by doing this?

Matt S
As the edit suggests I'm using reflection to build up a lot of things (mainly to be more DRY), and it is quite slow (at least in terms of overall running time: 95% is the setup time), but it only needs to be done once. I'm just curious on how the PHP community solves "problems" like this (or actually whether they solve these "problems" at all?).
SztupY
Matt S
I'm actually just curious. For the last 4 years I haven't been using PHP, and was used to how the other frameworks work. I like that they use a lot of reflection (mainly ASP.NET MVC) during the set up phase to be more DRY, and I wanted to do the same in PHP. Clearly PHP was not designed for fast reflection usage, but I don't care unless this only has to be done a few times and not for all requests.
SztupY
Matt S
+2  A: 

Not sure if APC is the only solution but APC does take care of all your issues.

First, your script will be compiled once with APC and the bytecode is stored in memory.

If you have something taking long time to setup, you can also cache it in APC as user data. For example, I do this all the time,

            $table = @apc_fetch(TABLE_KEY);

            if (!$table) {
                    $table = new Table(); // Take long time
                    apc_store(TABLE_KEY, $table);
            }

With APC, the task of creating table is only performed once per server instance.

ZZ Coder
Pre-compilation of the scripts is only part of the job. But if I see it corectly I have to do this part too using PHP, right? I mean for example mod_php won't do this for me.
SztupY
Code-caching is transparent. You just install APC and it will cache your byte-code automatically unless you disable it. Your app data like $table in my example will not be cached automatically. You have to do it yourself.
ZZ Coder
Why the hell are you suppressing `apc_fetch`? **`afc_fetch` returns the stored variable or array of variables on success; FALSE on failure**.
Alix Axel
@Alix Axel the script was running too fast.
efritz