delight-im / PHP-Foundation-Core

Core of “PHP-Foundation”
https://github.com/delight-im/PHP-Foundation
MIT License
6 stars 6 forks source link

Load member 'auth' in class 'App' lazily #9

Open bfinlay opened 5 years ago

bfinlay commented 5 years ago

Performing benchmark tests saw 50% performance improvement (from ~3500 req/sec to ~5300 req/sec) by creating the auth component lazily on a non-authenticated route - https://github.com/bfinlay/PHP-Foundation-Core/blob/master/src/App.php

I tested the possibility that this might be due to session handler files being created by the PHP session handler by ensuring that they were created on a tmpfs filesystem, but that did not have any impact positive or negative.

Benchmark test is here: https://github.com/bfinlay/FrameworkBenchmarks/tree/delight.im/frameworks/PHP/delight.im/app

ocram commented 5 years ago

Thank you very much!

As per this other issue:

The member $auth is instantiated immediately because it creates the session. Loading that component was done lazily before, but if you start a session in your application or read/write the $_SESSION globals, this won't work. So it was changed to load immediately again, which I don't see any way around, unfortunately.

It was ultimately reverted in this commit.

If we were able to load the authentication component lazily, we could also load the database component lazily (which does not create an actual connection to the database immediately).

But given the limitations above, we’d only ever be able to defer this if the developer does not use authentication or sessions at all, or if they marked certain routes as not using those (as in your example), with a mechanism that we don’t have yet.

bfinlay commented 5 years ago

That makes sense. I will give it some more thought and add some more comments later.

In our real project (not the benchmark project) we have been migrating from a platform that has its own session implementation and does not use php sessions, and so also does not use the $_SESSION globals. We first migrated the auth component to your PHP-AUTH component which is solid and well designed. (It took me months to realize that you had more framework beyond the PHP-AUTH component, and was thrilled to see that its design was largely what I envisioned building.)

We are not currently using a front controller, so nginx routes directly to the appropriate controller, and our user facing URLs are rendered and routed by our SPA. Only authenticated routes bootstrap the PHP-AUTH component. So far we have still been using the old platform's session management strategy and are currently migrating to use the PHP-AUTH session functionality. This required us to also implement a custom session_handler for session storage. That hasn't been as easy as was expected, and raises the question if the PHP session management functionality is better than the prior session management strategy, which was very straightforward.

When we authenticate with our legacy session strategy, if the user is not authenticated, we get back an anonymous session. So we haven't had any trouble of instantiating the auth and getting an anonymous session and any data that was saved with the anonymous session. (We minimize the amount of data stored in session.)

As we work through our migration to use the PHP-AUTH sessions I will compare with our previous strategy and I will develop some suggestions.

Thanks for considering.

ocram commented 5 years ago

Thanks for your appreciation and for the explanations on what you wanted to do and are currently doing.

Not instantiating the authentication component on truly anonymous, unauthenticated routes that really don’t care whether somebody is signed in or not is totally fine and will work. But this is only a common scenario with APIs, I guess.

With (server-rendered) web applications, you often have “mixed” routes that may either be unauthenticated or authenticated. An example may be the index page, which can contain some marketing messages for unauthenticated clients and the user’s dashboard, timeline, etc. for authenticated users. Apart from that, you often have routes that would actually be anonymous (e.g. your terms of service) but the navigation bar at the top requires authentication to either show the authenticated user’s navigation and profile picture or the unauthenticated navigation.

The default session handler of PHP should be fine, but the authentication component should also work with other session handlers, as long as you use the normal functions to start and manage sessions, like session_start, and access data via the $_SESSION array.