Autoloading on Autopilot

Autoloading on Autopilot

Autoloading is a wonderful feature in PHP that allows you to automatically include the files that your classes are in as they are referenced. Let's talk about how it works, how to do it, and all that goes with it, including namespaces, PSR standards, and Composer. Hopefully by the end of this discussion, autoloading will be so easy for you that it will feel like it's on autopilot.

Ca57a7cfac69ba3abf517470f3770aae?s=128

Jeremy Lindblom

August 11, 2015
Tweet

Transcript

  1. Autoloading on Autopilot by Jeremy Lindblom (@jeremeamia)

  2. About Me @jeremeamia

  3. • Includes • Autoloaders • Optimization • Namespaces • PSRs

    • Composer Autoloading on Autopilot
  4. — Includes —

  5. a.php CODE CODE include ‘b.php’; CODE Includes = Why I

    Started Using PHP b.php CODE CODE CODE CODE Executed code CODE CODE CODE CODE CODE CODE CODE
  6. Includes = Why I Started Using PHP header.php sidebar.php main.php

  7. None
  8. include include_once require require_once Including vs. Requiring What’s the difference

    between all of these?
  9. include include_once require require_once Including vs. Requiring On errors: include

    ➔ E_WARNING require ➔ E_COMPILE_ERROR “once”: Only loads file if you haven’t loaded it before.
  10. Including Classes - Not Fun <?php // NOTE: Assuming one

    class per file require_once(‘classes/user.class.php’); require_once(‘classes/page.class.php’); require_once(‘classes/role.class.php’); require_once(‘classes/db.class.php’); // ...
  11. The Bottom Line Explicit includes/requires are: 1. Necessary and helpful

    for procedural code. 2. Cumbersome and harmful for object- oriented code.
  12. — Autoloaders —

  13. What is an Autoloader? 1. A callback triggered when a

    non-existent class is referenced.
  14. What is an Autoloader? 1. A callback triggered when a

    non-existent class is referenced. 2. A function that provides a definition for a specified class name.
  15. What is an Autoloader? 1. A callback triggered when a

    non-existent class is referenced. 2. A function that provides a definition for a specified class name. “Providing a definition” can mean: • Loading a class from a file (include/require) • Dynamically creating a class (eval) • Aliasing an existing class (class_alias)
  16. Autoloader Advantages • Classes are loaded on demand ◦ No

    need to write specific include statements ◦ Class never loaded unless it’s needed • Leads to better code maintainability • Easy to write
  17. The Old Way – Includes everywhere require_once(‘classes/user.class.php’); require_once(‘classes/page.class.php’); // ...

    $page = Page::forTemplate(‘profile’); $page->set(‘user’, User::fetchById(5));
  18. Autoloading to the Rescue function __autoload($class) { $file = strtolower($class).‘.class.php’;

    require(‘classes/’.$file); } $page = Page::forTemplate(‘profile’); $page->set(‘user’, User::fetchById(5));
  19. Autoloading to the Rescue function __autoload($class) { $file = strtolower($class).‘.class.php’;

    require(‘classes/’.$file); } $page = Page::forTemplate(‘profile’); $page->set(‘user’, User::fetchById(5)); WHY NOT USE require_once?
  20. Implicit “Once” Autoloaders are only triggered if the specified class

    is not loaded, So… The “_once” is implied, since once you load a class, the autoloader won’t be called again.
  21. Implicit “Once” No need for these: • include_once • require_once

    Don’t use them anymore for loading classes.
  22. function __autoload($class) { $file = strtolower($class).‘.class.php’; require(‘classes/’.$file); } SOMETHING IS

    STILL WRONG WITH THIS CODE.
  23. function __autoload($class) { $file = strtolower($class).‘.class.php’; require(‘classes/’.$file); } YOU SHOULD

    NOT USE THIS FUNCTION SOMETHING IS STILL WRONG WITH THIS CODE.
  24. Please Use spl_autoload_register • Added in PHP 5.1.2 • Can

    register multiple autoloaders ◦ Allows third-party libraries to provide their own! • Can add an autoloader to the front or back of the autoloader queue • Any use of __autoload gets superceded by spl_autoload_register
  25. Please Use spl_autoload_register spl_autoload_register(function ($c) { if ($c === ‘Foo’)

    require ‘lib/foo.inc’; }); spl_autoload_register(function ($c) { $path = ‘classes/’.strtolower($c).‘.class.php’; if (file_exists($path)) require $path; });
  26. Errors in Autoloaders Do not throw exceptions or trigger errors

    in an autoloader. Give the rest of the chain a chance.
  27. — Optimization —

  28. BAD GOOD There are many ways to implement autoloaders.

  29. All classes in one file; no autoloader BAD GOOD

  30. Many autoloaders; Each can only load 1 class BAD GOOD

  31. BAD GOOD 2 1

  32. — Namespaces —

  33. Namespaces • Added in PHP 5.3 • Prevents naming collisions

    • Syntax: ◦ Before Namespaces: Zend_Http_Client ◦ With Namespaces: Zend\Http\Client • Allows aliasing
  34. Namespaces - Defining <?php namespace Zend\Http; class Client { //

    ... }
  35. Namespaces - Using <?php namespace SeaPhp\Example; use My\Orange\Carrot; use Foo\Bar

    as Bunny; $thing = new Bunny(new Carrot);
  36. None
  37. — PSRs & PHP-FIG —

  38. • FIG = Framework Interop Group • PSR - PHP

    Standards Recommendation ◦ Autoloading: PSR-0, PSR-4 ◦ Others: ▪ PSR-1, PSR-2 - Coding style ▪ PSR-3 - Logging interface ▪ PSR-7 - HTTP message interface PHP-FIG
  39. None
  40. Given class: Zend\Http\Client Load file: <source-root>/Zend/Http/Client.php Autoloading PSRs

  41. Example Implementation (incomplete) spl_autoload_register(function ($class) { $path = str_replace(‘\\’, ‘/’,

    $class); if (file_exists($path)) require $path; });
  42. — Composer —

  43. Composer - “Dependency Manager for PHP” • Installs dependencies (a.k.a.

    third-party libraries) into your project. • Creates an autoloader capable of autoloading everything in your project.
  44. Setting up Autoloading w/ Composer Your files: Project/ |- README

    |- composer.json |- src/ |- Foo.php (contains SeaPhp\Example\Foo) |- Bar.php (contains SeaPhp\Example\Bar)
  45. Setting up Autoloading w/ Composer In your composer.json: ... "autoload":

    { "psr-4": { "SeaPhp\\Example\\": "src/" } }
  46. Autoloading on Autopilot w/ Composer In your project root: $

    composer.phar install
  47. Autoloading on Autopilot w/ Composer In your index.php: <?php require

    ‘vendor/autoload.php’; use SeaPhp\Example\Foo; $foo = new Foo;
  48. None
  49. — Optimization — (Revisited)

  50. BAD GOOD 2 1

  51. BAD GOOD Composer autoloader (1 autoloader handles all classes)

  52. Classmap Autoloading In your project root: $ composer.phar dumpautoload -o

  53. Classmap Autoloading spl_autoload_register(function ($c) use ($paths) { if (isset($paths[$c])) require

    $paths[$c]; }); // vs. spl_autoload_register(function ($c) { $path = str_replace(‘\\’, ‘/’, $class); if (file_exists($path)) require $path; });
  54. BAD GOOD Composer dumped autoloader (1 autoloader; fast lookup; no

    file_exists)
  55. Summary of Best Practices 1. Don’t use include_once or require_once

    2. Use spl_autoload_register, not __autoload 3. Don’t throw exceptions in autoloaders 4. One class per file 5. Namespaces/classes match directories/files 6. Follow PSR-4 (or PSR-0) 7. Use Composer, even if no dependencies 8. Use classmap autoloaders in production
  56. Autoloading on Autopilot by Jeremy Lindblom (@jeremeamia)