{"id":568,"date":"2009-06-02T15:15:19","date_gmt":"2009-06-02T14:15:19","guid":{"rendered":"http:\/\/t-machine.org\/?p=568"},"modified":"2009-06-02T15:18:22","modified_gmt":"2009-06-02T14:18:22","slug":"php-include-once-require-once","status":"publish","type":"post","link":"http:\/\/new.t-machine.org\/index.php\/2009\/06\/02\/php-include-once-require-once\/","title":{"rendered":"Now I remember why PHP is so easy to hate&#8230;"},"content":{"rendered":"<p>(aka &#8220;why do my include\/require\/include_once\/require_once files not work \/ seem NOT to be included, even though they are?&#8221;)<\/p>\n<p>PHP has a mechanism for including files inside each other. The architects of PHP didn&#8217;t really think much about what they were doing with a lot of the core language features (witness the foolishness over Register Globals), and file import\/include\/require is a classic example.<\/p>\n<p>This is one of the most fundamental features of the language, and it&#8217;s screwed up. It &#8220;seems&#8221; to work, so long as you write simplistic enough \/ small enough apps. The bigger your app, the more likely it is you&#8217;ll discover how poor this part of the language is.<br \/>\n<!--more--><br \/>\nIn most languages, you have a distinction between<\/p>\n<ol>\n<li>importing (IMP)\n<li>including (INC)\n<li>internally-evaluating (INT)\n<li>externally-evaluating (EXT)\n<\/ol>\n<p>(not all languages have all of the above &#8211; most have 2 or 3 of them)<\/p>\n<p>The first one runs at the language-level, and is surrounded by all sorts of careful compiletime\/runtime code to manage exactly what happens. The second one runs at the source-file-level, and simply &#8220;dumps&#8221; the contents of another file inside the main file.  The last two are like the second, except that they &#8220;executes&#8221; the other file, and whatever that &#8220;execution&#8221; process outputs is what gets embedded &#8211; rather than the contents of the file. They differ from each other in that one executes using all the currently-in-scope info, the other executes without any access to currently scoped data.<\/p>\n<p>PHP says &#8220;**** it, I can&#8217;t be bothered with writing code properly, I&#8221;ll just pretend all four of those are identical, and I&#8217;ll name the functions as if I meant INC, even though I don&#8217;t&#8221;.<\/p>\n<p>Net result: the include\/require\/include_once\/require_once statements in PHP don&#8217;t really work properly, because they have to do the work BOTH of importing AND of including AND of evaluating &#8230; all in one go.<\/p>\n<p>(by the way &#8230; this is <a href=\"http:\/\/uk.php.net\/manual\/en\/function.include.php\">subtly documented in the fourth paragraph of the docs for include()<\/a>, but there&#8217;s no warning in the other statement\/function docs)<\/p>\n<p>Here&#8217;s the &#8220;compromises&#8221; that have been made (with the use-cases in brackets):<\/p>\n<ul>\n<li>Files are treated as plain HTML (INC)\n<li>&#8230;but also, simultaneously, as &#8220;executable, may contain PHP tags&#8221; (EXT)\n<li>When a file is brought in, it is only executed when that line of code is executed (INC, INT)\n<li>The scope of anything executed is the scope of the currently-executing function (INT)\n<li>Any (de facto) closures (in the form of defined functions) found inside the brought-in file &#8230; are shunted into the current environment (INC, IMP)\n<\/ul>\n<p>Several of those are clearly mutually incompatible already. It&#8217;s simply not possible to put all three of those features onto a single language-statement. Unfortunately &#8230; PHP has.<\/p>\n<p>That&#8217;s just irritating &#8211; it means that basic PHP apps suddenly break when you add a line of code, because e.g. you&#8217;ve been using include() to do EXT, or IMP, and that was fine &#8230; but you just added some code that expose it&#8217;s incompatible behaviour by showing off some of its INT functionality (or vice versa).<\/p>\n<p>But far worse is what happens when you throw &#8220;_once()&#8221; into the mix. In practical terms, it&#8217;s actually surprisingly easy to write code that doesn&#8217;t run correctly at runtime (and this is undocumented, too). Because &#8220;_once()&#8221; is, essentially, an undefined language feature.<\/p>\n<p>Don&#8217;t believe me? <a href=\"http:\/\/uk.php.net\/manual\/en\/function.include-once.php\">Go read the docs<\/a>. Find for me the point where they state the definition of:<\/p>\n<blockquote><p>&#8220;if the code from a file has already been included&#8221;<\/p><\/blockquote>\n<p>(or &#8230; don&#8217;t bother. Take my word for it &#8211; it&#8217;s not defined).<\/p>\n<p>If IMP, INC, and EVAL were *not* squashed into some ugly mess like they are in PHP, this *would not be a problem*, because people would just work on the &#8220;obvious&#8221; interpretation of &#8220;has already been included&#8221;, i.e.:<\/p>\n<blockquote><p>you called &#8220;include*()&#8221; or &#8220;require*()&#8221; on this filename already<\/p><\/blockquote>\n<blockquote><p>you called &#8220;include*()&#8221; or &#8220;require*()&#8221; on this filename AT THIS SCOPE already<\/p><\/blockquote>\n<p>What? TWO definitions? Well, yes, dear reader, because most humans will pick the first definition. It appears correct. And for IMP and EXT &#8211; by definition &#8211; it is correct, since they ignore scope. However, sadly, INC and INT explicitly require scope to be obeyed, and they *require* the second definition to be used.<\/p>\n<p>Guess which definition PHP uses? Bearing in mind that PHP *treats the include() file differently* depending upon which scope it&#8217;s imported at&#8230;<\/p>\n<p>Did you guess the second option? Ha! Wrong!<\/p>\n<p>And so, in PHP, it&#8217;s easy to write something like this:<\/p>\n<pre>\r\nfile 1:\r\nif( !isset( $A) )\r\n   $A = \"not blank\"\r\n\r\nfile 2:\r\nrun();\r\nfunction run()\r\n{\r\n   require_once 'file 1';\r\n   require_once 'file 3';\r\n}\r\n\r\nfile 3:\r\ncrashout();\r\nfunction crashout()\r\n{\r\n  require_once 'file 1';\r\n  if( isset($A) )\r\n    echo \"this will never happen!\";\r\n  else\r\n    echo \"PHP will claim that A is not set, even though\"\r\n      . \" it is explicit set in the file that is explicitly included above!\";\r\n}\r\n<\/pre>\n<p>I bashed my head against a wall with this (kind of) problem until I realised what was going on: PHP has a very poor definition of &#8220;a file has already been included&#8221;.<\/p>\n<p>And what the heck can you do to workaround this? Actually, I&#8217;m not sure yet. I&#8217;ve only recently worked out how and why the runtime does what it does. I&#8217;ve not yet worked out a simple approach to PHP programming that avoids the above problems, beyond &#8220;never use an include* statement from within a function &#8211; never ever, under any circumstances&#8221;. At least that forces the behaviour to be predictable (NB: as soon as you do an include* from within a function, each and every one of your PHP scripts will potentially cease to work). But it&#8217;s very annoying to be actively prevented from ever doing an INC\/INT\/EXT.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>(aka &#8220;why do my include\/require\/include_once\/require_once files not work \/ seem NOT to be included, even though they are?&#8221;) PHP has a mechanism for including files inside each other. The architects of PHP didn&#8217;t really think much about what they were doing with a lot of the core language features (witness the foolishness over Register Globals), [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[55,20],"tags":[],"_links":{"self":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/568"}],"collection":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/comments?post=568"}],"version-history":[{"count":0,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/568\/revisions"}],"wp:attachment":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/media?parent=568"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/categories?post=568"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/tags?post=568"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}