7

I'm writing a PHP application for the first time (other than toys and exercises), and I'm at a loss to understand why PHP includes both an include and a require construct.

Before you write an answer explaining the differences between the two, let me first say that I do understand the difference - include produces a warning and keeps on going, and require produces a fatal error. My question is: when would you want to include, but not require a file?

Maybe it's a failure of imagination on my part, but there don't seem to be any files in my application that I don't want to scream about if they're not there. Oddly, this doesn't make me want to use require since it seems impossible to properly handle a failed require, so instead I use a helper function along the lines of this (warning: air code):

public static function include($filename) {
  if (is_readable($filename)) {
    if (!@include($filename)) {
      throw new FileNotFoundException("File deleted after readable check");
    }
  } else {
    throw new FileNotFoundException("File missing or unreadable");
  }
}

I guess what I'm asking is:

  • What sorts of files would you really want to optionally include in an application?
  • Whether or not you want a file to be required or optional, why wouldn't you just handle that in a function like a modified version of the code I wrote above?
AgentConundrum
  • 20,288
  • 6
  • 64
  • 99
  • possible duplicate of [When should I use require_once vs include?](http://stackoverflow.com/questions/2418473/when-should-i-use-require-once-vs-include) – Gordon Nov 24 '10 at 08:55
  • @Gordon: I don't think this is a dupe, because I explicitly explain that I understand the differences between them, I just don't get why they're both necessary. The question you linked doesn't address either of the two bulleted questions I wrote at the bottom of this post. – AgentConundrum Nov 24 '10 at 08:58
  • @Agent read @Gordon's answer to that question, it goes in the right direction and is *way* better than the accepted one – Pekka Nov 24 '10 at 08:59
  • 1
    @Gordon -- I'd link to your answer, which I found more informative than the accepted one :) http://stackoverflow.com/questions/2418473/when-should-i-use-require-once-vs-include/2418580#2418580 – Nikki Erwin Ramirez Nov 24 '10 at 08:59
  • @Pekka: I didn't read that far down when he just linked it, but I guess I see his point now that I've read it. I still don't see the answer to either of my questions though. I still can't come up with an example file that should be included but not required. – AgentConundrum Nov 24 '10 at 09:05
  • 1
    @Agent possible example: `require 'defaultSettings.php'; include 'userProvidedOverloadForDefaultSettings.php';` Basically, anything that overwrites existing values or that doesnt immediately break your application when not given can be included. I agree most of the time you will want to use `require` though. – Gordon Nov 24 '10 at 09:08
  • @Gordon: I guess that makes sense, but it still seems to me that it makes more sense to keep it all under one roof for error handling, etc. - `die()` messages are ugly as hell and don't give me, as the developer, feedback when they occur. – AgentConundrum Nov 24 '10 at 09:14
  • @Agent Definitely, but keep in mind that Exceptions have not been available in PHP until PHP 5.1.0. The include and require statements have been in PHP for much longer. You have to take PHP's procedural roots into account. – Gordon Nov 24 '10 at 09:19
  • @Gordon: Oh, I definitely get that, even before asking this question I thought of that. Even before exceptions however, it wouldn't be hard to rewrite my sample code with a more procedural bent. Today it seems to me that `require` really isn't needed and might even be a good candidate for deprecation. – AgentConundrum Nov 24 '10 at 09:24
  • 1
    @Agent IMO, there is no point in trying to handle unhandable situations or throw an exception when it cannot be caught anyway. A missing Core Library is unhandable. The best you can do then is tell the user. But for that, you can just use `register_shutdown_function` and `error_get_last()` to see if there was an error and send a 500 header along with a pretty page. But then again, yes, you could use include and `set_exception_handler` for those unhandable cases too. I wouldn't think too much about it. Be pragmatic. Use what works. – Gordon Nov 24 '10 at 09:38
  • @Gordon: I'm pretty much a noob at this (From the question: "I'm writing a PHP application for the first time (other than toys and exercises)") so I don't really know the best way to do most things. I'm just trying to learn. I didn't even know about the functions you mentioned, though I'll look into them now. I'm just trying to make the best design I can, and give my (theoretical) users the best experience possible. Sorry to be a burden. ;) If you can guide me to a resource that'll teach me good error handling and design practices, I'll definitely check them out. – AgentConundrum Nov 24 '10 at 10:24
  • @Agent you're not a burden at all. I am just saying it's easier to use what works *now* than to spend too much time considering what might work *best*. That's not to say you shouldn't bother learning or planning ahead, but as software requirements change during the development phase, you will often find that the *best* design *now* isn't the best design *later*. That's why you should embrace change and familiarize yourself with [Refactoring](http://www.refactoring.com). For Error handling, see the [chapter in the PHP manual about it](http://de.php.net/manual/en/book.errorfunc.php) for a start – Gordon Nov 24 '10 at 10:34
  • 1
    @Gordon: That makes sense. After conversing a bit with @deceze under his answer, I realize how stupid my whole problem has been. If it ever gets to the point where an important class or template file is outright missing, either I screwed up royally and I need to confess and apologize, or something crazy happened to the server, in which case it was beyond my control and I have a perfectly good scapegoat in the hosting company ;) I really need to embrace the "what works now" philosophy. I keep falling into the traps of premature optimization and architecture astronautics. – AgentConundrum Nov 24 '10 at 10:41

2 Answers2

2

I'd use require for loading files essential for the app itself, i.e. require 'database_config.php', require 'core.php'. If this fails, you want it to fail as fast, hard and merciless as possible, since something is obviously wrong with your app installation. In this state it's not even guaranteed that it could handle a thrown exception properly, and require produces a very clear error message without any extra code.

include should be used for things like template files that you want to use when the app is already up and running and can handle its own errors gracefully.


Example:

include 'error_handler.php';
set_error_handler('error_handler');

/* something bad happens */

Warning: 'error_handler.php' not found!
Error: Specified error handler "error_handler" doesn't exist.

At some point you simply rely on basic files, even if it's just your error handler. You'd have to introduce extra code to handle a missing error handler gracefully, and even then the best you could do is output some error and die (unless you want to get into the game of catching errors gracefully even if your error handler doesn't exist). It's best to simply require 'error_handler.php'; you can include and custom handle everything after this if you want to.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • To me, a missing template file seems like a pretty critical thing. It indicates to me that either the app was deployed incorrectly or something critical (I do count "the thing that actually displays to the user" to be critical) has mysteriously vanished, leaving the app in an unstable state. I'd rather catch all of that in my function and throw an Exception that alerts me, rather than just throwing an ugly `die()` message at the user. Maybe I'm just not far enough along yet to have found a file that I don't consider critical. – AgentConundrum Nov 24 '10 at 09:10
  • 2
    @Agent I am sure @deceze did not mean `die` when saying *gracefully* ;) – Gordon Nov 24 '10 at 09:14
  • 1
    @Agent Sure, a missing template file is a terrible thing. That's why you try to `include` it and log errors, send emails and serve a 404 page **gracefully** if it can't be found. It's not a given that an application is able to do all these things when the basic `required` files aren't found, that's why you use `include` for one and `require` for the other. – deceze Nov 24 '10 at 09:18
  • @Gordon: In my question, I said I was against `require`. I'd rather just use `include` (or `include_once`) everywhere, wrapped in a function/helper class, that is graceful in *all* circumstances, but knows how to properly bitch when things really hit the fan. I didn't mean to imply that I thought @deceze was advocating for `die()` – AgentConundrum Nov 24 '10 at 09:19
  • @deceze: You're sort of making my case for me in your comment, since you're advocating for `include` in a critical case, which is exactly my point. I think `include` is enough for all circumstances, with proper error handling around it so that it can be useful even in critical would-use-require cases. – AgentConundrum Nov 24 '10 at 09:21
  • @Agent See updated answer for better example. If this doesn't convince you, well then, tough luck I guess. :o) – deceze Nov 24 '10 at 09:39
  • @deceze: I guess for your example I was pretty much planning to duplicate the wrapper around the call to include the helper class. Maybe that's not the best way, but I'm very much a noob here (which means I don't know how I'm "*supposed to*" handle these situations, and I'm paranoid (which means I'll go out of my way to make sure I'm nice to the user even in crazy impossible situations). – AgentConundrum Nov 24 '10 at 10:13
  • @Agent Once you get into this game, there's no end to it. At some basic level your application simply needs to fail hard and fast if some really basic required bits are missing. You'll probably notice these errors really quickly yourself, so the user should never see them. – deceze Nov 24 '10 at 10:32
0

What sorts of files would you really want to optionally include in an application?

I normally use include with static HTML blocks (header, footer, menu, search box, survey form...) and require with PHP functions or classes. It's unlikely that the footer block will disappear but, well, I suppose it's a nice visual clue when I look at the code.

Whether or not you want a file to be required or optional, why wouldn't you just handle that in a function like a modified version of the code I wrote above?

The @ operator is said to be expensive and, anyway, I think that including an external file is a basic operation that should be covered by basic language. Your code also adds a new dependency: if you store it in a required block your optional blocks will no longer be 100% optional ;-)

Álvaro González
  • 142,137
  • 41
  • 261
  • 360
  • I don't know how expensive the @ really is. I just ran some checks, and when I was actually writing data directly the error suppressed function was consistently faster (by quite a wide margin) than the unsuppressed version. I added `ob_start` to the beginning and `ob_clean` after all processing, and the unsuppressed version was slightly faster (0.04 seconds after 25k iterations of each). I moved `ob_clean` calls into each include function (i.e. so the buffer would be cleaned immediately after each include) and got similar results. Single data point, true, but the @ might not hurt that bad. – AgentConundrum Nov 24 '10 at 10:04
  • 1
    @Agent [Please heed the Warning in the PHP Manual](http://de.php.net/manual/en/language.operators.errorcontrol.php). You should avoid the error suppression operator at any cost. You dont want to troubleshoot your future 50k LOC application blindly :) – Gordon Nov 24 '10 at 10:52