spl_autoload Class not found following namespaces directory structure - php

I'm trying to use class autoloading in my project. This is what I wrote:
on main.php:
namespace myproject;
spl_autoload_extensions(".php");
spl_autoload_register();
subspace\myclass::mystaticmethod();
on subspace/myclass.php:
namespace myproject\subspace;
class myclass {
static function mystaticmethod() {
....
}
}
I get this error:
PHP Fatal error: Class 'myproject\\subspace\\myclass' not found
So far I've only found a problem with case sensitive names in the documentation, so I switched to lowercase only but I get the same error. Why?
[EDIT] Using PHP 5.3.3

I've found the problem: The default include directory would be the full namespace/subspace path.
I've also found a good solution. From http://www.php.net/manual/en/function.spl-autoload.php#92767:
<?php
// Add your class dir to include path
set_include_path(get_include_path().PATH_SEPARATOR.'..');
// Make autoloader look for commonly used "myclass.php" type filenames
spl_autoload_extensions('.php');
// Use default autoload implementation
spl_autoload_register();
?>
The default autoload implementation is written in C and is always slightly faster than a PHP one.

Related

Autoload namespaces based on directory structure

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!';
}
}
?>
In your someclass.php file you must define the namespace at the begginning.
<?php
namespace classes;
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)
Include Path
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.
Directory Separator mapping
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.
Case Sensitivity of File Names
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:
https://lxr.room11.org/xref/php-src%407.1/ext/spl/php_spl.c#spl_autoload
https://lxr.room11.org/xref/php-src%407.1/ext/spl/php_spl.c#307
PHP - most lightweight psr-0 compliant autoloader
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:
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
https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx
https://getcomposer.org/doc/01-basic-usage.md#autoloading
http://www.php-fig.org/psr/psr-0/
http://www.php-fig.org/psr/psr-4/
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.

PHP namespaces trouble

I just wanna use a namespace in another file, to use the class in it, but im too retarded to do this...
first file:
namespace fun;
use fun\kjr\trouble;
$trouble = new trouble('http://someURL');
second file:
namespace fun\kjr;
class trouble { ... }
This is the error i get:
Error: Fatal error: Class 'fun\kjr\trouble' not found in D:\wamp\www\fun\index.php on line 8
Where did I declare a wrong namespace? Oo
Greetings
I had to include my class aswell.
use namespace
only makes the class available in the actual context.
It does NOT include it, so you can cause it.
use
include_once('your.file')
to do that!
Thanks #Michael Berkowski for helping.
The problem (from what I can see) is you haven't specified an autoloader (e.g. with spl_autoload_register()) or haven't included the file in your code. The use statement will only find a class for you if you have an autoloader in place, otherwise you must include your code ahead of time with include/include_once or require/require once.
I would start with making an autoloader and registering it and then it may be wise to map your namespaces to directory structure as specified by PSR-0.

autoload and namespace

Suppose I have classes in same namespaces:
directory :
(folder) a
a.php
(folder) b
b.php
c.php
and we use namespace and __autoload as you see:
in folder b\b.php :
<?php
namespace b;
use b as x;
function __autoload($clsName){
$clsName='../'.str_replace('\\', '/', $clsName).'.php';
require_once $clsName;
}
class b{
function __construct(){
print("b file<hr/>");
}
}
$t=new x\c(); // line 13
?>
and in folder b\c.php :
<?php
namespace b;
class c{
function __construct(){
print("c file<hr/>");
}
}
?>
when we define $t=new x\c, __autoload doesn't call!
please help me :(
error message:
Fatal error: Class 'b\c' not found in C:\xampp\htdocs\project\TEST\b\b.php on line 13
You have not defined autoloader. PHP looks for __autoload (or \__autoload - function defined in global namespace) while you have defined only \b\__autoload (yes, functions are namespaced to!)
How to fix it: move __autoload declaration outside namespace
Better fix: you should use spl_autoload_register
It's hard to see exactly what is going wrong. By the looks of the error, it appears that the __autoload() function isn't being called. If it was I would expect the require_once statement to fail with an error saying file not found, or something like that.
You could try by putting some debugging statements in your __autoload() function to see what's going on, including a var_dump of your $clsName variable.
It might be worth noting the following message that appears in the PHP manual regarding autoloading:
spl_autoload_register() provides a more flexible alternative for
autoloading classes. For this reason, using __autoload() is
discouraged and may be deprecated or removed in the future.
You should also note, that there is a "standard" for PHP autoloading, called PSR-0. Here is a link to an article that gives a good explanation of it.
In both the article and the PSR-0 document mentioned above, are example autoloaders that you can use. I would suggest using one of these than trying to implement your own.

How to resolve a namespace on php?

I'm doing the first test on php5. More specifically I'm trying to work with namespaces but it seems that php is not resolving the namespace. Here the test I've done:
file 1: test.php
<?
namespace \first_test;
class Test {
function test_function(){
print "works";
}
}
?>
file 2: use_namespace.php
<?
use \first_test;
$a=new \first_test\Test();
$a->test_function();
?>
I get a fatal error:
Fatal error: Class 'first_test\Test' not found in
here_the_path_where use_namespace.php is.
Any help appreciated.
P.S. Both files are on the same directory, php 5.3.9 on windows.
You don't need the \ when declaring a namespace, you only need it when calling functions from it.
<?php
namespace first_test;
// ...
?>
Also, in your 2nd file, you need to include test.php, otherwise it doesn't know what first_test is.
In the 3rd-party library they most likely use autoloader, which automaticly does all the required includes. So if you dont want to manually write include, add your own autoloader
http://php.net/manual/en/language.oop5.autoload.php
It is a general aproach that you entry point contains autoloader, so all included files will use it automaticly. Description of coding standart for this can be found at https://www.php-fig.org/psr/psr-4/

I get this error when trying to autoload classes

I get this error when trying to autoload classes.
I declare this class in myclass.php file and instantiate it in test.php. but i got class not found error on xammp. Is _autoload function case sensitive in php.
class MyClass {
//some properties and methods
}
function __autoload($class_name) {
require_once($class_name.".php");
}
$myclass = new MyClass();
Anyone know what the problem is?
Make sure you define MyClass correctly in your myclass.php.Your problem is not caused by __autoload because the error is class not found instead of file not found which require_once would throw out if it fails.
Class names and function names in PHP are not case-sensitive, but your autoloader must use the correct case when using require* or include* because your OS filesystem may be case-sensitive. And if your autoloader uses relative paths, make sure the classes invoked are in PHP's include_path.

Categories