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

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.

Jeremy Lindblom

August 11, 2015
Tweet

More Decks by Jeremy Lindblom

Other Decks in Programming

Transcript

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

    View Slide

  2. About Me
    @jeremeamia

    View Slide

  3. ● Includes
    ● Autoloaders
    ● Optimization
    ● Namespaces
    ● PSRs
    ● Composer
    Autoloading on Autopilot

    View Slide

  4. — Includes —

    View Slide

  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

    View Slide

  6. Includes = Why I Started Using PHP
    header.php
    sidebar.php main.php

    View Slide

  7. View Slide

  8. include
    include_once
    require
    require_once
    Including vs. Requiring
    What’s the difference
    between all of these?

    View Slide

  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.

    View Slide

  10. Including Classes - Not Fun
    // 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’);
    // ...

    View Slide

  11. The Bottom Line
    Explicit includes/requires are:
    1. Necessary and helpful for
    procedural code.
    2. Cumbersome and harmful for object-
    oriented code.

    View Slide

  12. — Autoloaders —

    View Slide

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

    View Slide

  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.

    View Slide

  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)

    View Slide

  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

    View Slide

  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));

    View Slide

  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));

    View Slide

  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?

    View Slide

  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.

    View Slide

  21. Implicit “Once”
    No need for these:
    ● include_once
    ● require_once
    Don’t use them anymore for loading classes.

    View Slide

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

    View Slide

  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.

    View Slide

  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

    View Slide

  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;
    });

    View Slide

  26. Errors in Autoloaders
    Do not throw exceptions or trigger
    errors in an autoloader.
    Give the rest of the chain a chance.

    View Slide

  27. — Optimization —

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  31. BAD
    GOOD
    2 1

    View Slide

  32. — Namespaces —

    View Slide

  33. Namespaces
    ● Added in PHP 5.3
    ● Prevents naming collisions
    ● Syntax:
    ○ Before Namespaces: Zend_Http_Client
    ○ With Namespaces: Zend\Http\Client
    ● Allows aliasing

    View Slide

  34. Namespaces - Defining
    namespace Zend\Http;
    class Client {
    // ...
    }

    View Slide

  35. Namespaces - Using
    namespace SeaPhp\Example;
    use My\Orange\Carrot;
    use Foo\Bar as Bunny;
    $thing = new Bunny(new Carrot);

    View Slide

  36. View Slide

  37. — PSRs & PHP-FIG —

    View Slide

  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

    View Slide

  39. View Slide

  40. Given class:
    Zend\Http\Client
    Load file:
    /Zend/Http/Client.php
    Autoloading PSRs

    View Slide

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

    View Slide

  42. — Composer —

    View Slide

  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.

    View Slide

  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)

    View Slide

  45. Setting up Autoloading w/ Composer
    In your composer.json:
    ...
    "autoload": {
    "psr-4": {
    "SeaPhp\\Example\\": "src/"
    }
    }

    View Slide

  46. Autoloading on Autopilot w/ Composer
    In your project root:
    $ composer.phar install

    View Slide

  47. Autoloading on Autopilot w/ Composer
    In your index.php:
    require ‘vendor/autoload.php’;
    use SeaPhp\Example\Foo;
    $foo = new Foo;

    View Slide

  48. View Slide

  49. — Optimization —
    (Revisited)

    View Slide

  50. BAD
    GOOD
    2 1

    View Slide

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

    View Slide

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

    View Slide

  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;
    });

    View Slide

  54. BAD
    GOOD
    Composer dumped autoloader
    (1 autoloader; fast lookup; no file_exists)

    View Slide

  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

    View Slide

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

    View Slide