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_SEPARATOR
when 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
.php
when 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:
$ mkdir -p ~/php/tp2-1
$ cd !$ # go to new created directory
$ wget https://raw.github.com/willdurand-edu/php-practicals/master/files/psr0.tgz
$ tar xvfz psr0.tgz
$ rm psr0.tgz
$ 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
│ └── Chinon.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\Chinon' => 'Wine/Chinon.php',
];
Now, test your code:
$ php test_cache.php
You should see:
Coffee\Bali
Coffee\BlueMontain
Coffee\Sumatra
Soda\Lemonade
Soda\Juice\Orange
Wine\Bordeaux
Wine\Chinon
Fix the vendor/autoload_namespace.php
file to load classes based on namespaces.
Test your code:
$ php test_namespace.php
You should see:
Coffee\Bali
Coffee\BlueMontain
Coffee\Sumatra
Soda\Lemonade
Soda\Juice\Orange
Wine\Bordeaux
Wine\Chinon
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:
$ 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.php
using thevar_export()
method.
You can jump to: Practical Work #2 - Part 2.