Dan Q's PHP Cookery Class

An intro to PHP for Web Revivalists

Lesson 4: Includes and Functions

Objectives

  • Separate your site into smaller, reusable parts, and include them where they're needed
  • Write your own functions to encapsulate repetitive tasks
  • Share functions across multiple pages with include or require

As we saw with loops, PHP is very helpful when you want to reduce repetition in your code. This in turn reduces the risk of mistakes, and makes it easier to re-use the same code in multiple places.

One powerful way to do this is with PHP's include directive. This lets you load the contents of a PHP (or HTML) file into another PHP file.

With this, we can re-use the navigation menu we made in Lesson 3 on every page of our site, like this:

<?php
include('../03-lists-and-loops/navigation-menu.php');
?>

<article>
  <h2>Page title</h2>
  <p>
    Page content goes here.
  </p>
</article>

This shares your navigation menu across every page of your site, including any logic embedded within it (e.g. to conditionally show or hide menu items). Updating the menu in just one place updates it everywhere.

A common technique is to put reusable part of your site, like your header and footer, into separate files for reuse. Why not take a look at the source code for the header and the footer of this site!

PHP has several functions for including files, with slight differences between them. They are:

  • include - includes the file if it exists
  • require - includes the file; stops execution if it doesn't exist
  • include_once - includes the file if it hasn't been included yet and it exists
  • require_once - includes the file if it hasn't been included yet; stops execution if it doesn't exist

Purists get into arguments about which is better, but it usually only matters if your included file defines its own functions (in which case including it twice can cause an error).

Reusing common patterns with functions

So far, you've been using standard functions like strrev (to reverse a string) and date (to get the current date). You can write your own functions and they're a great to way to encapsulate reusable code.

Let's define a function for adding a captioned image, where clicking on it links to the full-size image:

<?php
/**
 * Renders a captioned image. Takes the following parameters:
 * - $url: The URL of the image to display.
 * - $alt: The alt text for the image.
 * - $caption: The caption to be displayed below the image.
 * - $max_width: The maximum width of the image in pixels;
 *               optional - defaults to 100 (pixels).
 */
function cap_img( $url, $alt, $caption, $max_width = 80 ) {
  ?>
  <figure>
    <a href="<?php echo $url; ?>">
      <img src="<?php echo $url; ?>"
          alt="<?php echo $alt; ?>"
        style="max-width: <?php echo $max_width; ?>px;
               height: auto;">
    </a>
    <figcaption><?php echo $caption; ?></figcaption>
  </figure>
  <?php
}
?>

<p>
  Things in my fruitbowl:
</p>

<div class="gallery">
  <?php
  /* Now we'll use our function to display a gallery: */
  cap_img( '/img/fruit/apple.jpg', 'A red apple',
          'From the tree in my back yard.' );

  cap_img( '/img/fruit/bananas.jpg', 'Two ripe bananas',
          "They're my favorite fruit." );

  cap_img( '/img/fruit/plums.webp', 'A bowl of purple plums',
          'I enjoy making jam every Autumn.' );

  cap_img( '/img/fruit/kiwi.jpg', 'A halved kiwi fruit',
          'I wish these grew in my part of the world.' );
  ?>
</div>

Sharing a function across multiple pages

To make that function available throughout our site, we can move it to a different file and then include or require it from the files that need it.

The shared file with the function:

<?php
// ( this is the file cap-img.php )

/**
 * Renders a captioned image. Takes the following parameters:
 * - $url: The URL of the image to display.
 * - $alt: The alt text for the image.
 * - $caption: The caption to be displayed below the image.
 * - $max_width: The maximum width of the image in pixels;
 *               optional - defaults to 100 (pixels).
 */
function cap_img( $url, $alt, $caption, $max_width = 80 ) {
  ?>
  <figure>
    <a href="<?php echo $url; ?>">
      <img src="<?php echo $url; ?>"
          alt="<?php echo $alt; ?>"
        style="max-width: <?php echo $max_width; ?>px;
               height: auto;">
    </a>
    <figcaption><?php echo $caption; ?></figcaption>
  </figure>
  <?php
}

A page that depends on it:

<?php
/*
 * Load our cap_img() function so we can make a gallery. We use
 * `require_once` so that we don't accidentally load it twice,
 * and so that if it fails to load the page stops here!
 */
require_once('cap-img.php');
?>

<p>
  Things in my fruitbowl:
</p>

<div class="gallery">
  <?php
  cap_img( '/img/fruit/apple.jpg', 'A red apple',
          'From the tree in my back yard.' );

  cap_img( '/img/fruit/bananas.jpg', 'Two ripe bananas',
          "They're my favorite fruit." );

  cap_img( '/img/fruit/plums.webp', 'A bowl of purple plums',
          'I enjoy making jam every Autumn.' );

  cap_img( '/img/fruit/kiwi.jpg', 'A halved kiwi fruit',
          'I wish these grew in my part of the world.' );
  ?>
</div>

The files you include can come from anywhere on your server, including from outside the directory (folder) where your publicly-accessible files are stored. On this site, for example, the "footer" can be viewed as if it were a standalone page by going direcly to https://php.danq.dev/inc/footer.php! How could you mitigate this by moving the footer into a different directory? (🏁 view solution)