Difference between include and require in PHP

Summary

In PHP applications, particularly in WordPress environments, the distinction between include and require centers on how they handle missing files. require is fatal on failure, terminating execution immediately, while include issues a warning and continues execution. This difference dictates architectural safety, particularly when loading optional components or handling conditional file paths.

Root Cause

The root cause of confusion—and bugs—lies in treating these constructs as interchangeable despite their distinct error handling behaviors.

  • require: Throws a fatal error (E_COMPILE_ERROR) if the target file is missing. The script stops executing.
  • include: Throws a warning (E_WARNING) if the file is missing. The script continues running, often leading to silent failures where classes or functions are undefined.
  • require_once / include_once: These variants check if a file has already been loaded. If it has, they do not load it again. The “once” suffix relates to the loading mechanism, not the error handling.

Why This Happens in Real Systems

In legacy codebases or plugins, developers often use include for templating (e.g., include 'header.php') assuming the file exists. If a file is moved or deleted, the page may render partially or break dynamically later in the execution flow.

Conversely, using require for optional configuration files that might not exist in every environment (e.g., local vs. production) can crash the entire application unnecessarily. The lack of strict typing in older PHP versions exacerbated this, as developers rarely explicitly checked file_exists() before including.

Real-World Impact

  • Maintenance Nightmare: Using include for critical dependencies causes “Class not found” errors that are difficult to trace because execution continued after the file failed to load.
  • Security Risks: Dynamic includes (include $variable) combined with include allow for Local File Inclusion (LFI) attacks if input isn’t strictly sanitized, as the script doesn’t halt if the file is invalid.
  • Unexpected Behavior: A missing include in a footer might leave a database connection open or locks unreleased because the cleanup code at the end of the script is never reached due to an earlier dynamic include failure.

Example or Code

How Senior Engineers Fix It

Senior engineers enforce strict consistency to eliminate ambiguity:

  1. Default to require: Use require for all class definitions and mandatory configuration files. It is better for the application to fail fast and visibly than to run in a broken state.
  2. Use require_once for Autoloading: Always use require_once when including classes manually to prevent “Cannot redeclare class” errors.
  3. Guard Clauses: Never rely on error suppression. Instead, use explicit checks:
    if (file_exists($path)) {
        require $path;
    } else {
        throw new Exception("Configuration file missing: $path");
    }
  4. Modernize: Move away from direct includes entirely by adopting PSR-4 autoloading standards. This removes manual file loading and relies on the Composer autoloader to handle dependencies safely.

Why Juniors Miss It

  • Copy-Paste Culture: Juniors often copy code snippets from tutorials that use include for everything because it “seems to work” without immediate errors.
  • Fear of Breaking the App: Juniors worry that a require error will crash the site, so they use include to keep the page “running,” not realizing that a silent failure is often more damaging than a loud crash.
  • Misunderstanding Scope: They may not grasp that require is a compile-time statement (in terms of execution order), making it safer for dependencies, whereas include acts more like a runtime function.