Reputation: 365
According to the top comment on the PHP
page spl_autoload_register( )
:
Good news for PHP 5.3 users with namespaced classes:
When you create a subfolder structure matching the namespaces of the >containing classes, you will never even have to define an autoloader.
<?php
spl_autoload_extensions(".php"); // comma-separated list
spl_autoload_register();
?>
However, when I have the following structure:
* classes/someclass.php
* index.php
Where someclass.php
contains the following:
<?php
class someclass {
function __construct( ) {
echo 'It works!';
}
}
?>
and index.php
contains:
<?php
spl_autoload_extensions(".php");
spl_autoload_register();
new classes\someclass;
?>
Then I get the following error:
Fatal error: spl_autoload(): Class classes\someclass could not be loaded
Am I getting this wrong? How can I make this work?
From the comments
This doesn't work either for the class:
<?php
namespace classes;
class someclass {
function __construct( ) {
echo 'It works!';
}
}
?>
Upvotes: 8
Views: 2806
Reputation: 41
Do not use the spl_autoload_extensions () function if the files to load only have the php extension. In my case, I create a class called autoload .. something similar to this:
<?php
class Autoload
{
private static $_extensions = array(
0 => '.inc',
1 => '.lib.php',
2 => '.class.php',
);
public function __construct()
{
self::set_include_path();
spl_autoload_extensions(implode(',', self::$_extensions));
spl_autoload_register(__CLASS__, 'load_class');
}
public static function set_include_paths()
{
set_include_path(implode(PATH_SEPARATOR, array(
realpath('classes');
realpath('system');
...
get_include_path();,
)));
}
public function load_class($class)
{
if (!empty($class)) {
spl_autoload($class);
}
return false;
}
}
The use of ?>
At the end of the file is not necessary.
Upvotes: 0
Reputation: 9582
Do not roll your own autoloading, but use composer
instead.
Create a composer.json
in the root of your project:
{
"autoload": {
"psr-4": {
"classes\\": "classes/"
}
}
}
Install composer
, then run
composer dump-autoload
In your index.php
, require the autoloader:
require __DIR__ . '/vendor/autoload.php';
For reference, see
Upvotes: 2
Reputation: 197767
TLDR; It works, but:
namespace classes;
is missing in classes/someclass.php
set_include_path(__DIR__);
is missing in index.php
spl_autoload_extensions(".php")
is not necessary)The SPL autoload implementation is include path based. Using a dot as include path is relative to the working directory (!) which is independent from script file location. __DIR__
names the exact directory that is needed if the classes
folder lies next to the index.php
file as in the scenario.
Next the autoloader implementation does map the class namespace separator properly on Unix systems. In case that got lost in the o/p, the PHP source code clearly has this.
What the source code also shows is that file-names to load are made lowercase. That is, if your file system is case sensitive, the file and directory names must be in lower case.
Refernces:
Upvotes: 5
Reputation: 1377
The user, SedaSoft, who had posted the Good news comment you which you refer, had subsequently posted another comment, due to a revision of ideas:
What I said here previously is only true on Windows. The built-in default autoloader that is registered when you call
spl_autoload_register()
without any arguments simply adds the qualified class name plus the registered file extension (.php
) to each of the include paths and tries to include that file.Example (on Windows):
include paths:
- "." - "d:/projects/phplib"
qualified class name to load:
network\http\rest\Resource
Here's what happens:
PHP tries to load
'.\\network\\http\\rest\\Resource.php' -> file not found
PHP tries to load
'd:/projects/phplib\\network\\http\\rest\\Resource.php' -> file found and included
Note the slashes and backslashes in the file path. On Windows this works perfectly, but on a Linux machine, the backslashes won't work and additionally the file names are case-sensitive.
That's why on Linux the quick-and-easy way would be to convert these qualified class names to slashes and to lowercase and pass them to the built-in autoloader like so:
<?php spl_autoload_register( function ($pClassName) { spl_autoload(strtolower(str_replace("\\", "/", $pClassName))); } ); ?>
But this means, you have to save all your classes with lowercase file names. Otherwise, if you omit the strtolower call, you have to use the class names exactly as specified by the file name, which can be annoying for class names that are defined with non-straightforward case like e. g.
XMLHttpRequest
.I prefer the lowercase approach, because it is easier to use and the file name conversion can be done automatically on deploying.
Note that this commenter had actually posted an answer here on SO today, containing the above links (along with a short explantation), but it was subsequently deleted, whilst in the review queue - presumably due to its brevity. I have reinstated the commenter's answer, along with the content of the link. Their answer was as follows:
I wrote that comment on php.net some time ago when I was working on a Windows system. Later, I had to partially revoke what I wrote in that comment on the very same page in another comment, which also contains a possible solution to the problem that is the easiest I could think of (apart from using Composer).
Here is a screenshot of the original answer:
Upvotes: 2
Reputation: 5721
In your someclass.php file you must define the namespace at the begginning.
<?php
namespace classes;
Upvotes: 5