PHP Code organization

Code organization

It is considered a good practice to keep web application code divided between a public directory and a private directory. Application frameworks often use this division as a default. Webservers can be configured to server content out of the public directory only. Web requests cannot be access the other files directly, just the ones in public, however the pages in public can still access code in the private directory via the file system.

Put PHP pages the public needs to access in the public directory.

  • primary PHP pages
  • images and other media
  • stylesheets
  • javascript

Put PHP pages which assist your public pages in the private directory.

  • classes
  • functions
  • database connectivity
  • credentials/passwords
  • template, layout, or partial page files

As a general rule, you want to try to keep code in the public PHP pages simple. Move complex code into functions in a separate file.


Adding content from other files

include() is a PHP function for including code from other files into a PHP page.

Using include() to bring secondary files into a primary file has a few advantages.

  1. Allows developers to keep their code organized in distinct files.

  2. Allows classes, functions, database credentials to be kept in a publicly inaccessible directory. The public should never be able to view PHP code in a public directory either. PHP code gets processed by the server and is never sent to the browser as PHP. However, if PHP processing were disabled for a page--either because the web server's PHP processing module becomes disabled or because of a syntax error in the PHP code—sensitive information could be exposed.

  3. Allows developers to not repeat code. "Don't repeat yourself" is a fundamental programming principle. Having code defined only one time gives cleaner, easier-to-understand code and reduces the chance of bugs.

Example using include()

// private/shared/header.php
<div id="header">This is the header.</div>

// private/shared/footer.php
<div id="footer">This is the footer.</div>

// public/page.php
<?php include('../private/shared/header.php'); ?>

<div id="content">
  <h1>Main page</h1>
  <p>This is content on the main page.</p>
</div>

<?php include('../private/shared/footer.php'); ?>

Notice that the path provided to the file is a Unix-style file path. It use ".." to indicate that it should go up one directory-level before it looks in "/private/shared/" for "header.php". This "backing up a directory" is precisely what PHP code can do to access these files that the user cannot do from their browser.


Including functions

It is good code organization to put functions into a different file which gets included into your primary file. This allows a developer to maintain a library of functions which can be used on multiple pages throughout a project. Functions could be further divided into several files organized by function type or purpose.

// private/functions/general.php
<?php

  function full_name($first_name, $last_name) {
    $result = $first_name . " " . $last_name;
    return $result;
  }

?>

// page.php
<?php include('../private/functions/general.php'); ?>
<?php include('../private/shared/header.php'); ?>

<div id="content">
  <h1>Main page</h1>
  <p>This is content on the main page.</p>
</div>

<?php include('../private/shared/footer.php'); ?>

Included files need their own opening and closing PHP tags if they contain PHP code. They should not depend on the PHP tags from the calling file. PHP processing gets turned off when the include starts. This makes sense because the first content in the included file could be HTML, not PHP.


PHP functions to include files

include() is only one of the four PHP functions which can add other content. All four functions will include a page into the current page, but the other three offer some additional features.

  • include()

  • require()

    • raises fatal error if page not found
  • include_once()

    • remembers included paths; ignores previously included
  • require_once()

    • raises fatal error if page not found
    • remembers included paths; ignores previously required

Usage Advice

In most cases, include() and require() are interchangeable. Files are not usually missing from our project. Most PHP developers choose to use require() all of the time.

The functions include_once() and require_once() are very useful for functions because functions will raise an error if they are redefined accidentally. These functions use the provided file path to keep track of what has been loaded, and they can be tricked if given different paths to the same file. Try to always use the same file path.

NEVER include files provided by users. If their file contains PHP code, it will execute their code on the server as if it were a trusted resource. This is the single worst choice a PHP developer could make from a security standpoint.


Using Constants and Absolute Paths

The functions include() and require() will accept either a relative path or an absolute path to a file.

PHP files live inside directories which can be nested inside many other directories. At some point, referring to files by their relative path to the current file can get tricky. And the relative path will be different for files nested at different levels which can cause confusion.

// your_project/public/states.php
<?php include('../../private/shared/header.php'); ?>

// your_project/public/staff/states/index.php
<?php include('../../../../private/shared/header.php'); ?>

One handy technique is to determine the absolute path to a directory and assign it to a PHP constant. Then the constant will be a shorthand for the path to the directory.

For example, you could put code like this into "your_project/private/initialize.php" and make sure it is the first code to be run.

<?php
  // Assign path shortcuts to PHP constants
  // __FILE__ returns the current path to this file
  // dirname() returns the path to the parent directory

  define("PRIVATE_PATH", dirname(__FILE__));
  define("PROJECT_PATH", dirname(PRIVATE_PATH));
  define("SHARED_PATH", PRIVATE_PATH . '/shared');
  define("PUBLIC_PATH", PROJECT_PATH . '/public');
?>

Of course your PHP page will need to navigate to initialize.php initially, but then you will have constants to use thereafter to build paths for include and require.

// your_project/public/states.php
<?php include(SHARED_PATH . '/header.php'); ?>

// your_project/public/staff/states/index.php
<?php include(SHARED_PATH . '/header.php'); ?>

Important Note These are only for internal file paths for use with include() and require(). It is not for use with URLs or links.

Fork me on GitHub