{"id":38,"date":"2011-06-26T23:34:21","date_gmt":"2011-06-26T23:34:21","guid":{"rendered":"http:\/\/tech.avant.net\/q\/?p=38"},"modified":"2012-12-25T22:40:47","modified_gmt":"2012-12-25T22:40:47","slug":"php-namespaces-and-class-loading","status":"publish","type":"post","link":"https:\/\/tech.avant.net\/q\/php-namespaces-and-class-loading\/","title":{"rendered":"php Namespaces and Class loading"},"content":{"rendered":"<p>I want to autoload php classes and functions. Ideally, I want a lazy loader (include class files only when they are needed, never including more files than necessary).  I&#8217;d also like namespace protection (if running PHP 5.3 or later).  And of course I want to do this easily without having to keep track of hierarchical dependency chains.<\/p>\n<p>PHP provides a magic function called __autoload() which can be leveraged to this end. You can implement __autoload() directly, OR you can use the spl_autoload functions. There is a default spl_autload() that provides namespace support (mapping namespaces to lowercase directories, classname to lowercase filename, and extension to .inc or .php)<\/p>\n<p>Given two namespaces &#8216;foobar&#8217; and &#8216;snafoo&#8217;; and lowercase filenames representing the class name (e.g., foobar\\Foo() class would be located in foobar\/foo.php) you could simply use the default spl_autoload() function as follows:<\/p>\n<pre class=\"sh_php\">\r\n&lt;?php\r\n  spl_autoload_register();\r\n\r\n  $foo1 = foobar\\Foo();\r\n  $foo2 = snafoo\\Foo();\r\n?&gt;\r\n<\/pre>\n<p>However, I would like my files to match the class names directly, e.g., &#8220;class FooBar&#8221; should be in a file named &#8220;FooBar.php&#8221; rather than &#8220;foobar.php&#8221;.<\/p>\n<p>Also, to support legacy code written in PHP 5.2 and before, I would like the autoloader to search for underscore-based long class names, e.g., &#8220;class legacy_snafoo_FooBar&#8221; would be located in &#8220;legacy\/snafoo\/FooBar.php&#8221;.  Prefixing a classname with an underscored-namespace has been an unofficial solution to the lack of PHP namespaces for years.<\/p>\n<p>Fortunately, spl_autoload_register allows you to chain multiple autoload functions, and you can keep the default spl_autoload() at the top of the chain to maintain much faster performance autoloading namespace-based code. <\/p>\n<p>Here is a custom autoload implementation with namespace support, legacy long-classname suppport, as well as honoring multiple file extensions. Note the use of a closure requires PHP 5.3<\/p>\n<pre class=\"sh_php\">\r\n&lt;?php\r\n\/*\r\n * Custom autoload callback\r\n * * maintains spl_autoload_extensions\r\n *\/\r\nfunction delimiter_autoload ($delimiter) {\r\n  return function($className) use ($delimiter) {\r\n    $extensions = explode(',', spl_autoload_extensions());\r\n    foreach($extensions as $ext) {\r\n      $classFile = str_replace($delimiter,DIRECTORY_SEPARATOR,$className) . $ext;\r\n      if (is_file($classFile)) {\r\n        include_once($classFile);\r\n        break;\r\n      }\r\n    }\r\n  };\r\n}\r\n\/*\r\n * register autload functions\r\n *\/\r\nspl_autoload_extensions('.php,.inc,.class.php,.lib,.lib.php');\r\nspl_autoload_register();\r\nspl_autoload_register(delimiter_autoload('\\\\'));\r\nspl_autoload_register(delimiter_autoload('_'));\r\n\r\n?&gt;\r\n<\/pre>\n<p>The actual application code is now free to instantiate based on any namespace or legacy classname (using the underscore-approach), e.g.,<\/p>\n<pre class=\"sh_php\">\r\n&lt;?php\r\n  $foo1 = foobar\\Foo();\r\n  $foo2 = snafoo\\Foo();\r\n  $oldfoo = legacy_foobar_Foo();\r\n?&gt;\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I want to autoload php classes and functions. Ideally, I want a lazy loader (include class files only when they are needed, never including more files than necessary). I&#8217;d also like namespace protection (if running PHP 5.3 or later). And of course I want to do this easily without having to keep track of hierarchical [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[7],"tags":[],"_links":{"self":[{"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/posts\/38"}],"collection":[{"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/comments?post=38"}],"version-history":[{"count":10,"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/posts\/38\/revisions"}],"predecessor-version":[{"id":739,"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/posts\/38\/revisions\/739"}],"wp:attachment":[{"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/media?parent=38"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/categories?post=38"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/tags?post=38"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}