Dependency management via Include
s/require_once
s in php is a pain. Every once in a while I change things and stuff breaks and I have to rethink my approach to initializing the very first include()/require() in php. I feel like I'm missing a more robust technique that would work and solve all my problems, but I just don't seem to have found it yet.
Autoloading with a mvc would be nice! But for legacy procedural projects I don't think that's a help?
Probably like everyone else, I started out with relative pathing. require_once('../../../core/core.php');
for example. Unfortunately that breaks when you start requiring libraries that have their own required dependencies. So then I moved to using a dynamic include that parses out the main project folder from any location that is up the hierarchy: require_once(substr(dirname(__FILE__), 0, strpos(dirname(__FILE__), 'my_project')+8).'core/database/admin.database.connection.php');
this meant I could past this anywhere that the permissions where appropriate, and move it -anywhere- in the project and it would still work!. Unfortunately, it broke when I implemented CI and the CI project set a project root like: /home/rof/bitbucket.org/repo_name/clone/
which didn't include the specific string "my_project" and thus broke all the includes. So for the past hour or so I've been fixing includes, and it's not fun. I want to find a "final solution".
Currently I have been changing the includes to:
require_once(realpath(__DIR__.'/../../').'/core/database/admin.database.connection.php');
Unfortunately, if I move a group of scripts up or down a directory (like moving users/orders/ into admin/orders or all the various housekeeping approaches) that's going to require rewriting each-individual-script again. Changing the DIR.'/../../' to DIR.'/../../../' or whatever. It sucks because it's so complex that it's scary to try to rewrite it project or directory wide, stuff will probably just break.
What is the final solution for non-object-oriented, procedural/function-based php projects with complex directory structures?
Here's an nearly real directory structure, which is pretty standard, but just to give you an idea:
core/
- core.php
- environment.php
- database/
- database.php
- admin.database.connection.php
- user.database.connection.php
- public.database.connection.php
www/
- index.php
- contactus.php
- map.php
- ...
- users/
- login.php
- logout.php
- accountdetails.php
- ...
- admin/
- login.php
- logout.php
- index.php
- admin.php
...
- reports/
- revenue_report.php
- orders.php
- clientslist.php
- orders/
- orderslist.php
- orderview.php
...
Hopefully you get the idea, an old legacy system with procedural code, many complex scripts, and multiple tiers of database access.
I've worked with these kind of problems a lot now, and here is what I would highly highly suggest in all cases: route everything through a front controller as soon as possible!
In php it is exceedingly beneficial to create a front controller and handle all your scripts through it, as soon as you can set it up. If you still have legacy scripts like example.php
, have your front-controller index.php
include them in a whitelisted way! So a url like mydomain.com/example would route through front-controller, get all the basic includes, and only then include the example.php
script if whitelisted!
Anything else is just delaying the inevitable problems of unifying a fractured codebase full of lots of tiny separated scripts.
Regardless of a procedural design, you must have some common files, e.g. a config.php
with your db connection information.
So you can set up some definitions in there:
First, your app's base path, relative to the config file...
define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../'); // or whatever
note, since PHP 5.3 you can use __DIR__
instead of dirname(__FILE__)
You can then set up individual definitions for each set of files. Maybe:
define('CORE_PATH', APPLICATION_PATH . '/core/');
Then in your individual scripts you can just do
include(CORE_PATH . 'database/admin.database.connection.php');
Or if you want to fine-tune it, define a path for /core/database/
instead, and do e.g. include(CORE_DATABASE_PATH . '/admin.database.connection.php');
If you move these folders around, you just need to update your config file.