Approaching dynamic php includes on legacy projects without a front controller

312 views Asked by At

Dependency management via Includes/require_onces 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?

Past approaches

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 Using

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.

My goals

  • 1st Simplicity, I want to set the includes and be certain they'll work & forget about them.
  • 2nd Tiered system so that different areas can include libraries with different access levels
  • 3rd I don't want to have to rewrite includes when things change. Ideally, I'd love to write the includes in one place for admin access, one place for user access, and one place for public access.

What is the final solution for non-object-oriented, procedural/function-based php projects with complex directory structures?

Example Directory Structure & Scripts

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.

2

There are 2 answers

0
Kzqai On BEST ANSWER

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.

3
rjdown On

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.