Having covered downloading and installing PHP and setting up a development environment, I'm now actually going to talk about writing PHP code! Specifically, I will describe how I boot my PHP scripts and why I boot them the way I do. Part 1 shows how my requirements for code portability and maintainability influence the boot process. Part 2 will go into more detail about the specific steps executed by the boot code.
My environment
Here's some background: I develop sites for multiple clients. Initial coding occurs on my Windows XP system. When the code is running well, I upload it to the client's hosting system, which is typically Linux based.
I start by creating a new directory for my client's Web files (on my PC) and then creating an alias in my Apache configuration file to point to this location. For this article, let's assume I reach the Web site using http://localhost/sample.
A sample task
For our first PHP class, let's tackle something easy—let's use PHP code to generate our sample site's navigation menu. Here's a quick sketch of the navigation class:
<?php class Navigation { public function printMainNav() { echo '<ul><li><a href="index.php">Home</a></li>....'; } } ?>
and here is the index.php page using the class:
<?php require 'Navigation.inc'; ?> <html> <head> ... </head> <body> <?php $navigation = new Navigation(); $navigation->printMainNav(); ?> ... </body> </html>
At this point, the directory we created contains two files:
- index.php
- Navigation.inc
The code works, but we're already seeing some potential pitfalls. First, we don't want to place the PHP classes in the same directory as the Web pages. Secondly, our sample system will eventually grow to where we will use sub-directories to organize our Web pages. The problems we see are:
- Each Web page will need to include the Navigation.inc file based on the Web file's location. If we ever change our mind about where to place Navigation.inc, a lot of files will need changes.
- The link to the home page (in the navigation), as written, only works for Web pages at the top of the directory tree.
It may seem that there are some easy work-arounds for these two problems. For instance, setting the path to the Navigation.inc file in the php.ini file solves the first problem. And linking to "/sample/index.php", solves the second. The reason these solutions aren't ideal lies with the environment in which I work.
Goals and requirements
These are my goals:
- I want to use a consistent approach for all my clients.
- I want to allow for sub-directories in the Web site.
- I want all Web files to have a consistent way of including PHP code, regardless of their location on the site. This lets me use the same template for all files and to move a file from one place to another without having to edit it.
- I don't want the Web pages to use any complicated calculations in order to include PHP code. Complicated code should be stored in one place, not scattered in every Web page.
- I want to be able to upload the code from my Windows system to the hosting system without any changes and have it work in both environments.
- Occasionally, I also want the code to work without change on a testing site on the hosting system. This lets the client preview site changes without affecting the site the customers sees.
These are the restrictions I have:
- I can't alter the php.ini file since shared hosting services usually don't provide access to this file.
- I can't place php_flag or php_value statements in the .htaccess file. These only work if PHP is run as an Apache module and some hosting companies use Fast CGI. (Note: apparently, this limitation will disappear in PHP 5.3.)
- I can't assume I can reference a Web page at the top of the site by starting the path with "/". This might work for the final site, but not for the site on the PC, where the top is at /sample.
My current solution
I have not found the perfect solution. What I use is pretty close:
- Each Web page begins with <?php require 'include.inc'; ?>.
-
Each Web site directory contains an include.inc file with the
following contents:
<?php $fileTop = '.'; require "$fileTop/res/boot/boot.inc"; ?>
The advantages are:
- We can move Web files from one directory to any other without editing.
- The variable $fileTop identifies the file path to the top of the root of the Web site.
- $fileTop is a relative path, so the Web site tree can be located anywhere in the site's document root.
It's not a perfect solution because I still have to create one include.inc file per directory. Of course, that's not very many files and the contents are not complicated. Any heavy lifting can be relegated to the boot.inc file.
It's also not perfect because it requires an extra file load for the include.inc file.
It assumes that '.' is in the php.ini search path. So far, this has proven to be a safe assumption.
Alternatives
Drupal and a number of other systems use a common dispatcher page for all Web site accesses. Every page loads index.php, which then includes the desired content. $fileTop is always '.'.
Using Apache's mod_rewrite module, the process could work like this:
- The user enters http://www.sample.com/somepage.
- Mod_rewrite converts this to http://www.sample.com/index.php?q=somepage.
- The index.php file is loaded.
- The index.php can directly contain the boot.inc code. This saves one include/require.
- It uses the 'q' parameter to determine which page the user really wanted.
- That Web page somepage.inc is included.
This eliminates two file includes. There is some hidden cost in that the mod_rewrite script probably has to do a file check to see if the requested Web file actually exists—this allows access to CSS, Javascript and image files that you may not want handled by PHP.
One problem with this approach is that my Web pages can set some options before loading the include.inc file and these options control aspects of the boot process (e.g. whether to use caching, whether to use sessions, etc.). I will discuss this more in Part 2 of this article; we might lose this flexibility in the single dispatcher approach or we might have to work around it in a way that voids the performance gain. Not having tried this alternative, I'm not sure of the answer.
Do you have an even better approach? Please let me know.
More to come
In Part 2, I will discuss what happens when the boot.inc file is executed. Stay tuned!




Better Portability
There are potentially better methods than $fileTop = ".";. For example, $fileTop = dirname(__FILE__); is a great way to add portability to your code (I tend to prefer to leave the somewhat ambiguous "." operator out of my path's). As you know __FILE__ is the literal location of the file the code is executing in (not the file that included the code). dirname() just extracts the directory
Also for code portability, consider using the DIRECTORY_SEPARATOR constant instead of "/". It guarantees operation in a windows environment (where directories are separated by ") and a linux-based environment.
Finally consider the __autoload() and spl_register_autoload() functions. If you are placing your class files in a common directory or have a common naming convention, you can use the __autoload() magic function to automatically include (at the time of need) the file for a class that is trying to be accessed. spl_register_autoload() is best as it allows you to add an __autoload() function without worrying about overwriting a previously existing one (say if you dropped your code in with some other code that used __autoload() as well)
Re: Better Portability
Daniel, thank you for your thoughtful suggestions. I have a few comments on your response:
Thanks again for taking the time to write. I appreciate all comments.
Tony Freixas
still not sure
may be I am dumb
But I am still not sure how to use dirname(__FILE__) . '/..' thing
For example I have this structure
lib/a.php
b.php
c.php
dir/e.php
Now a.php includes c.php further a.php is included every page like b.php or dir/e.php.
How to mane this, please help.
Hi, Abhi,
Let me try to answer your question. The first clarification is that, in my scheme, the include.inc file that I create is needed only for directories that hold PHP Web "pages"—these are the files that the server calls in response to an HTTP request.
Files that are included by other PHP files do not need to worry about booting, but they do need to use the $fileTop variable when including or requiring another PHP file.
So: a.php has:
b.php and dir/e.php both have
Now I'm going to guess that b.php and dir/e.php are called directly by the server. Normally, I would keep an included file like c.php in a different folder and I would use the ".inc" extension, but that's not important. The top level and the "dir" directories both have an include.inc file. The top level include.inc contains:
The "dir" include file contains:
So both b.php and dir/e.php would start like this:
With $fileTop set appropriately, both b.php and dir/e.php will be able to include lib/a.php and lib/a.php will also be able to find c.php.
I hope this answers most of your question. The dirname(__FILE__) technique is just an alternate way of calculating $fileTop's value.
Tony Freixas
Post new comment