Slide 1

Slide 1 text

Autoloading on Autopilot by Jeremy Lindblom (@jeremeamia)

Slide 2

Slide 2 text

About Me @jeremeamia

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

— Includes —

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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.

Slide 10

Slide 10 text

Including Classes - Not Fun

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

— Autoloaders —

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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.

Slide 15

Slide 15 text

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)

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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?

Slide 20

Slide 20 text

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.

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

— Optimization —

Slide 28

Slide 28 text

BAD GOOD There are many ways to implement autoloaders.

Slide 29

Slide 29 text

All classes in one file; no autoloader BAD GOOD

Slide 30

Slide 30 text

Many autoloaders; Each can only load 1 class BAD GOOD

Slide 31

Slide 31 text

BAD GOOD 2 1

Slide 32

Slide 32 text

— Namespaces —

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

Namespaces - Defining

Slide 35

Slide 35 text

Namespaces - Using

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

— PSRs & PHP-FIG —

Slide 38

Slide 38 text

● 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

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

— Composer —

Slide 43

Slide 43 text

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.

Slide 44

Slide 44 text

Setting up Autoloading w/ Composer Your files: Project/ |- README |- composer.json |- src/ |- Foo.php (contains SeaPhp\Example\Foo) |- Bar.php (contains SeaPhp\Example\Bar)

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

Autoloading on Autopilot w/ Composer In your index.php:

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

— Optimization — (Revisited)

Slide 50

Slide 50 text

BAD GOOD 2 1

Slide 51

Slide 51 text

BAD GOOD Composer autoloader (1 autoloader handles all classes)

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

Autoloading on Autopilot by Jeremy Lindblom (@jeremeamia)