4

A framework I'm writing (for learning) requires a specific PHP version to run, so I'm implementing a "PHP version check" to ensure the running PHP version is the minimum required for the framework.

Basic setup

htaccess redirects everything to index.php (front controller);
index.php loads bootstrap.php (nothing else);
bootstrap.php loads the core components (error display setting; error logging; user settings; then routes the requested URI);

Problem

If the version check code or anything loaded before it requires a PHP version higher than the one running, the check itself and anything before it will fail.

Crude option

Loading the version check code first would work, but the framework has logical structure, with classes in specific places called as needed with SPL and DI. And for this to work it would have to be a basic conditional in index.php (front controller), but I'm trying to avoid this because:

  1. index.php is no place for such code
  2. It will have no access to other framework functionality, and output wouldn't be through framework template but a raw message: exit('invalid PHP version');
  3. The required PHP version (e.g. "50400") is "config" data, and should live in core/config/. Updating/managing the required version is not ideal in index.php

Additionally, the version check code itself has a PHP version requirement.
e.g. The check uses PHP_VERSION_ID to get the current running PHP version, which requires PHP 5.2.7.
I could use another method, but really then I'm piling all sorts of code into index.php, and it's not supposed to be like that.

So the code being first to load in index.php and being a conditional is making me cringe, as it should be a nice class calling on Core config (etc) and it doesn't belong like this in front controller as a cheap conditional.
But, maybe I have no choice.

For example, first code in index.php (so first code to run before anything else):

if (!defined('PHP_VERSION_ID') || (PHP_VERSION_ID < 50400)) {
  exit ('Insufficient PHP Version');
}

I really cannot see any way around doing it like this, as with classes (etc) the framework needs a certain PHP version to even get to a class to check the version, and if the version is too low it'll error and even the version check class won't run.
It's the "chicken and the egg" problem.

Question

I'm looking for a solution on how to resolve this, in terms of a better software architecture and design approach.
Or, am I stuck as I think I am because having functionality run before the version check means a potential application error?

Or..

Am I trying to resolve something which does not need to be resolved?
And instead just need to state "This framework needs PHP v X.X.X, running it on lower version will bring problems".

4

Starting with the last question, documenting the framework requirements is a must, but having the version check will be useful for those foolish enough not to read the documentation.

Having the minimum version as a configurable option doesn't make complete sense, as the minimum version is an intrinsic property of the code itself, not something external to the code that might vary from site to site. It's in the same category as the framework's version number, license, and main website (though these are all extrinsic properties). If you move the minimum version from configuration to package metadata, the problem becomes much easier.

Since the version check is part of initializing the framework, it makes sense to add it to the "bootstrap.php" initializing script, either inline or by calling some function or method with sanity checks. The latter would be a good choice if other requirements, such as for non-core extensions, exist or are likely to crop up.

Another sensible design is to add requirements checks to the installation procedure, if there is one. This is both an optimization (there's little-to-no need to check requirements with every page request) and makes conceptual sense, as installation is global initialization. This assumes that either the server configuration regarding the framework requirements won't change, or that any changes that get made won't affect the requirements (e.g. version requirements are only for minimal versions and no component will get downgraded), which are fairly reasonable assumptions (until PHP-next happens to come around). If you don't want these assumptions, you could add a server fingerprinting module based on the requirements. If the fingerprint changes, the server has changed and the requirements checks are re-run. The fingerprint check could be done on a per-request basis for all pages or only admin pages. Of course, the fingerprint calculation & check may be more expensive than the requirements check, so it may offer no advantage.

That the requirements check could be handled during installation or per-request initialization is good support for the argument that the checks themselves should be in a separate module, rather than inline.

The remaining issue is how to handle version check failure according to best practices. Since bootstrap.php shouldn't be concerned with displaying anything, it should only detect the version. Displaying an error message should be left to some framework component. To avoid another dependency cycle, you could design a component with minimum requirements that handles fatal errors (such as requirements failures, DB failures and the like) that's loaded by the bootstrap first-thing. This could be part of the controller, if it has (or can be made to have) minimal requirements.

  • Thanks for taking the time to read and answer. So you think have the version check as an integral part of the framework, logically placed like all other components, and it's enough having that and in download/readme/documentation/etc stating "PHP version X required"? Some cases (it's likely) the user will have min PHP version for the version check to work. If not, then "they didn't read the docs"? – James Jul 13 '15 at 14:25
  • I think I have error message sorted. Framework has core/view (it's framework relevant code only, not front end view - i.e. not website files). core/view has a basic controller and templates to output framework problems/errors in a simple styled way if the system cannot continue. These are not loaded/invoked unless there is an unrecoverable fault (it shouldn't happen given the system is tested, but as they're only called when needed, I find it a nice backup to have). This is invoked when, i.e., wrong PHP version, or when URI is not found and neither is the user defined "not found" page. – James Jul 13 '15 at 14:33
  • @James: The version check in code and the documented requirements should cover everything you can. What other precautions are you envisioning? As for core/view, sounds good. – outis Jul 13 '15 at 23:45
  • Ok thanks :) "Other precautions" is probably me being too picky and wanting perfection where it's not required, or not possible. My aim was an end user to never have a borked system where it "just doesn't work". I want them to always get a framework exit/error message. e.g. if they use the system with incorrect PHP version, they get "Sorry, PHP 5.1 is not adequate, upgrade to PHP 5.4", however I feel I'm attempting to cater for things beyond a sane reach (certainly without compromising quality code etc) – James Jul 14 '15 at 0:24
  • @James: A laudable goal, but laziness can be a virtue. In this case, consider the opportunity costs. Note your sample code already covers the PHP version requirement for all versions of PHP. If you have other requirements, it's best to keep their checks simple rather than to cover edge cases (the development- & run-time costs likely exceed the benefits). – outis Jul 14 '15 at 0:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.