In this practical, you are going to create a PSR-0 compliant autoloader.
The following describes the mandatory requirements that must be adhered to for autoloader interoperability.
- A fully-qualified namespace and class must have the following
structure
\<Vendor Name>\(<Namespace>\)*<Class Name> - Each namespace must have a top-level namespace ("Vendor Name").
- Each namespace can have as many sub-namespaces as it wishes.
- Each namespace separator is converted to a
DIRECTORY_SEPARATORwhen loading from the file system. - Each
_character in the CLASS NAME is converted to aDIRECTORY_SEPARATOR. The_character has no special meaning in the namespace. - The fully-qualified namespace and class is suffixed with
.phpwhen loading from the file system. - Alphabetic characters in vendor names, namespaces, and class names may be of any combination of lower case and upper case.
\Doctrine\Common\IsolatedClassLoader=>/path/to/project/lib/vendor/Doctrine/Common/IsolatedClassLoader.php\Symfony\Core\Request=>/path/to/project/lib/vendor/Symfony/Core/Request.php\Zend\Acl=>/path/to/project/lib/vendor/Zend/Acl.php\Zend\Mail\Message=>/path/to/project/lib/vendor/Zend/Mail/Message.php
\namespace\package\Class_Name=>/path/to/project/lib/vendor/namespace/package/Class/Name.php\namespace\package_name\Class_Name=>/path/to/project/lib/vendor/namespace/package_name/Class/Name.php
The standards we set here should be the lowest common denominator for painless autoloader interoperability. You can test that you are following these standards by utilizing this sample SplClassLoader implementation which is able to load PHP 5.3 classes.
Four steps to achieve your goal:
- implement autoloading from cache;
- implement autoloading from namespace;
- implement autoloading using underscore notation;
- register the discovered classes in cache and dump it.
Get the code:
vagrant@vm $ wget https://raw.github.com/willdurand-edu/php-practicals/master/files/psr0.tgz
vagrant@vm $ tar xvfz psr0.tgz
vagrant@vm $ rm psr0.tgz
vagrant@vm $ cd psr0
Running the tree command should display the following:
.
├── generate.php
├── test.php
├── test_cache.php
├── test_namespace.php
├── test_underscore.php
└── vendor
├── Coffee
│ ├── Bali.php
│ ├── BlueMontain.php
│ └── Sumatra.php
├── Soda
│ ├── Juice
│ │ ├── Orange.php
│ │ └── Pineapple.php
│ └── Lemonade.php
├── Wine
│ ├── Bordeaux.php
│ └── Chateaugay.php
├── autoload.php
├── autoload_cache.php
├── autoload_namespace.php
└── autoload_underscore.php
Every class under vendor/ directory prints its name in the constructor:
<?php
class Foo
{
public function __construct($log = true)
{
if ($log) {
printf("%s\n", get_class($this));
}
}
}The SPL allows you to register a custom autoloader through
the spl_autoload_register() and spl_autoload_unregister() methods.
This part will be tested thanks to the test_cache.php script.
Register a closure as an autoloader in vendor/autoload_cache.php.
The closure MUST use the following associative array:
$autoload_map = [
'Coffee\Bali' => 'Coffee/Bali.php',
'Coffee\BlueMontain' => 'Coffee/BlueMontain.php',
'Coffee\Sumatra' => 'Coffee/Sumatra.php',
'Soda\Lemonade' => 'Soda/Lemonade.php',
'Soda\Juice\Orange' => 'Soda/Juice/Orange.php',
'Wine\Bordeaux' => 'Wine/Bordeaux.php',
'Wine\Chateaugay' => 'Wine/Chateaugay.php',
];Now, test your code:
vagrant@vm $ php test_cache.php
You should see:
Coffee\Bali
Coffee\BlueMontain
Coffee\Sumatra
Soda\Lemonade
Soda\Juice\Orange
Wine\Bordeaux
Wine\Chateaugay
Fix the vendor/autoload_namespace.php file to load classes based on namespaces.
Test your code:
vagrant@vm $ php test_namespace.php
You should see:
Coffee\Bali
Coffee\BlueMontain
Coffee\Sumatra
Soda\Lemonade
Soda\Juice\Orange
Wine\Bordeaux
Wine\Chateaugay
Fix the vendor/autoload_underscore.php file to successfully execute
test_underscore.php.
Hint: Don't Repeat Yourself (DRY), in other words, reuse the work that has been done before.
Then again, test your code by running:
vagrant@vm $ php test_underscore.php
You should see:
Soda\Juice\Pineapple
Fix the vendor/autoload.php file in order to fully comply to PSR-0.
The following steps SHOULD be executed:
- Load cache file;
- check whether the class is already in cache, if so load it;
- find class in definition map and add it to the cache;
- save cache array in
vendor/cache.phpusing thevar_export()method.
You can jump to: Practical Work #2 - Part 2.