Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Namespaces and Autoloading (Madison PHP Conference 2014)

23d971deeb3975a7d28246192fbbe7b7?s=47 Beau Simensen
September 13, 2014

Namespaces and Autoloading (Madison PHP Conference 2014)

Want to make sure that your class names don't overwrite the class names for any other projects on the server? Hate having long class names like [insert ridiculously long classname here]? Namespaces were introduced in PHP 5.3 to help address these common issues. Learn how to namespace classes and see how namespaces and class autoloading can make your coding experience much nicer!

23d971deeb3975a7d28246192fbbe7b7?s=128

Beau Simensen

September 13, 2014
Tweet

Transcript

  1. Madison PHP Conference September 13th, 2014 Namespaces and Autoloading @beausimensen

    beau.io joind.in/11741
  2. Namespaces

  3. since 5.3.0

  4. What problems do namespaces solve?

  5. COLLISIONS

  6. class Highlander { }

  7. THERE CAN BE ONLY ONE

  8. # class User { } include "src/user.inc"; ! # class

    User { } include "vendor/3rd-party/lib/user.php" ! PHP Fatal error: Cannot redeclare class User
  9. Commodity Names User Item Session Factory! List Client Post Entry

    Server Log! Cache Logger Input Command! ...
  10. Traditional Solutions

  11. AcmeUser

  12. sfUser

  13. PEAR_User

  14. Disadvantages

  15. What if you have more than one [thing] in your

    project?
  16. AcmeAccountUser! AcmeGroupUser

  17. sfAccountUser! sfGroupUser

  18. PEAR_Account_User! PEAR_Group_User

  19. People tried to organize class names like this

  20. It tended to lead to very deep class naming hierarchies

  21. substrate_stones_factory _IStoneClassLoaderAware

  22. Blech

  23. Extremely long class names can be found throughout most legacy

    PHP projects
  24. We've exposed another use case for namespaces

  25. OrG a nI Za Tion

  26. So namespaces really help solve two problems

  27. Collision Prevention and Organization

  28. How?

  29. \

  30. The \ is used to separate namespaces from classes and

    other namespaces
  31. AcmeAccountUser AcmeGroupUser

  32. Acme\Account\User Acme\Group\User

  33. –Anyone who has ever programmed “But isn't \ the string

    escape character?”
  34. "Acme\Account\User" "Acme\Group\User"

  35. "Acme\Account\User" "Acme\Group\User"

  36. \\

  37. "Acme\\Account\\User" "Acme\\Group\\User"

  38. { "autoload": { "psr-0": { "Dflydev\\Cilex\\Provider\\DoctrineOrm\\": "src", "Dflydev\\Pimple\\Provider\\DoctrineOrm\\": "src", "Dflydev\\Silex\\Provider\\DoctrineOrm\\":

    "src" } } }
  39. Using \ can be awkward, but it is better than

    some of the alternatives that were considered
  40. (really, PHP?) :)

  41. ... :>

  42. (designing a language is hard) ** ^^ %% :::

  43. The namespace Keyword

  44. Namespaces must be declared before any other code (except for

    declare)
  45. More than one namespace can be declared in the same

    file
  46. namespace Acme; class User { }

  47. Acme\User namespace Acme class User

  48. namespace Acme\Account; class User { }

  49. Acme\Account\User namespace Acme\Account class User

  50. You cannot tell just by looking if a string represents

    a namespace or a class
  51. Acme\Account\User Acme\Account\User\Acl Acme\Account\User\Group

  52. namespace Acme\Account; ! use Acme\Account\User; ! class User { public

    static function err($message) { throw new User\Exception\SomeError($message); } } ! namespace Acme\Account\User\Exception; ! class SomeError extends \Exception { } ! \Acme\Account\User::err("Confused Yet?");
  53. It can seem arbitrary and confusing

  54. It helps to think of namespaces representing a filesystem

  55. helps to think of namespace representing a filesystem

  56. PHP does not care where you put your namespaces and

    classes on disk!
  57. But if you use a filesystem as an analogy for

    namespaces...
  58. The namespace keyword tells you where you are in the

    filesystem
  59. namespace Acme\Account; class User { } ! $ cd Acme/Account

    $ touch User.php ! # Acme/Account/User.php
  60. namespace Acme\Account; throw new Exception\SomeError("hi"); ! $ cd Acme/Account $

    cat Exception/SomeError.php ! # Acme/Account/Exception/SomeError.php
  61. namespace Acme\Account; throw new Exception("wait, what?"); ! $ cd Acme/Account

    $ cat Exception.php ! # Acme/Account/Exception.php
  62. namespace Acme\Account; throw new \Exception("oh, i see!"); ! $ cd

    Acme/Account $ cat /Exception.php ! # Exception.php
  63. $user = new Acme\Account\User(); ! $ cat Acme/Account/User.php ! #

    Acme/Account/User.php
  64. $user = new \Acme\Account\User(); ! $ cat Acme/Account/User.php ! #

    Acme/Account/User.php
  65. How do namespaces address the [incredibly long class name here]

    problem mentioned earlier?
  66. The use Keyword

  67. Namespaces and classes can be imported into a file or

    namespace
  68. namespace Acme\Store\Controller; ! use Acme\Account\User; ! $user = new User();

    ! # User = Acme\Account\User
  69. namespace Acme\Store\Controller; ! use Acme\Account; ! $user = new Account\User();

  70. namespace Acme\Store\Controller; ! use Acme\Account\Errors; ! throw new Errors\AccountPastDue();

  71. Two namespaces or classes of the same name cannot be

    imported by use at the same time
  72. namespace Acme\Store\Controller; ! use Acme\Account\Errors; use Acme\PayPalClient\Errors; ! PHP Fatal

    error: Cannot use Acme \PayPalClient\Errors as Errors because the name is already in use
  73. namespace Acme\Store\Controller; ! use Acme\Account\Errors; use Acme\PayPalClient\Errors; ! PHP Fatal

    error: Cannot use Acme \PayPalClient\Errors as Errors because the name is already in use
  74. Namespaces and classes can be aliased when they are imported

  75. namespace Acme\Store\Controller; ! use Acme\Account\Errors as AccountErrors; use Acme\PayPalClient\Errors as

    PayPalErrors; ! if ($user->isBad()) { throw new AccountErrors\BadUser( "you know what you did" ); } try { $paypal->tryToCharge($user); } catch (PayPalErrors\TransactionError $e) { throw new AccountErrors\TransportError($e); }
  76. namespace Acme\Store; ! use Silex\Controller as BaseController; ! class Controller

    extends BaseController { }
  77. namespace Acme\Account\User; ! use Exception; ! throw new Exception("yay!"); !

    # Exception.php
  78. namespace Acme\Account; ! use Acme\Account\User; ! class User { public

    static function err($message) { throw new User\Exception\SomeError($message); } } ! namespace Acme\Account\User\Exception; ! class SomeError extends \Exception { } ! \Acme\Account\User::err("A little less confusing?");
  79. Autoloading

  80. Just use your classes

  81. # Acme\User is not defined ! $user = new Acme\User();

    ! # Acme\User is defined
  82. Magic!

  83. You probably won't use most of what you are about

    to learn directly... (it is good history to know, though!)
  84. __autoload since 5

  85. The __autoload function is called anytime a class does not

    exist
  86. function __autoload($class) { if ($class === "Acme\\Account\\User") { // do

    something to cause this class // to become defined require __DIR__."/src/user.inc"; } }
  87. The major limitation of __autoload is that it is only

    one function
  88. spl_autoload_register since 5.1.2

  89. With spl_autoload_register more than one autoloader implementation can be registered

    at the same time
  90. spl_autoload_register( // Registers Acme's autoloader Acme::autoloader ); ! spl_autoload_register( //

    Registers Doctrine's autoloader Doctrine::autoloader ); ! spl_autoload_register(function($class) { // Register a rarely used class if ($class === "Acme\\RarelyUsed\\User") { require __DIR__."/src/user.inc"; } });
  91. It's a stack!

  92. Don't write an autoloader

  93. Use an off-the-shelf autoloader

  94. None
  95. This means you will have to follow an autoloading standard

  96. PSR-0

  97. PHP-FIG PHP Framework Interoperability Group

  98. PSR-0 Autoloading Standard

  99. –Larry Garfield "For sufficiently vague definitions of 'accepted', May 2009

    is the date I use."
  100. Remember the filesystem analogy?

  101. PSR-0 essentially codified that concept and made it a thing

  102. Namespaces become directories

  103. Classes become files with .php suffix

  104. Acme\Account\User

  105. Acme/Account/User.php

  106. PSR-0 also supports legacy PEAR style naming conventions

  107. Acme\Account\User ! Acme_Account_User

  108. Acme/Account/User.php ! Acme/Account/User.php

  109. Legacy rules are kinda convoluted

  110. _ is converted to / but only in the class

    name
  111. Acme\Web_Site\User_Controller

  112. Acme/Web_Site/User/Controller.php

  113. PSR-0 had a handful of other relatively insignificant* issues *

    the significance of the issues varies wildly depending on who you ask
  114. PSR-0 was widely adopted by PHP-FIG member projects

  115. This led to PSR-0 being widely adopted

  116. None
  117. { "autoload": { "psr-0": { "Acme\\Account\\": "src" } } }

    ! new Acme\Account\User(); ! # src/Acme/Account/User.php
  118. { "autoload": { "psr-0": { "Acme_Account_": "src" } } }

    ! new Acme_Account_User(); ! # src/Acme/Account/User.php
  119. PSR-4

  120. PHP-FIG PHP Framework Interoperability Group

  121. PSR-4 Autoloading Standard Dec 3rd, 2013

  122. Overall same idea as PSR-0 in that it maintains a

    direct relationship between namespaces and the filesystem
  123. Only supports namespaces and does not support legacy naming conventions

  124. Introduces a namespace prefix and a base directory for mapping

  125. Acme\Account\User (class) ! Acme\Account (namespace prefix) ! src (base directory)

    ! src/User.php (resulting file path)
  126. The namespace prefix and base directory were influenced by widespread

    Composer adoption
  127. Trimming the "extra directories" addressed some people's complaints about PSR-0

  128. Dropping support for legacy naming simplified PSR-4 autoloader implementations

  129. None
  130. { "autoload": { "psr-4": { "Acme\\Account\\": "src" } } }

    ! new Acme\Account\User(); ! # src/User.php
  131. [this page intentionally left blank]

  132. So, namespaces and autoloading...

  133. Namespaces are useful for collision prevention and organization

  134. Don't write an autoloader

  135. Use an autoloading standard

  136. None
  137. joind.in/11741 Questions? @beausimensen beau.io ddd.io/madisonphp2014-namespaces

  138. Beau Simensen @beausimensen beau.io

  139. #composer look for simensen and say "hi" freenode IRC

  140. Dragonfly Development @dflydev dflydev.com

  141. boogio.com @wearboogio reflxlabsinc.com @reflxlabs