PHP autoloader cant find necessary class - php

So I am learning PHP MVC for the first time, and i came up to a term - autoloading all the required .php files.
So I searched the web for some examples, and made an autoload file with spl_autoload_register method, calling an anonymous method to require_once all needed files. I don't know what is wrong, but it seems not to work.
So the spl_autoload_register method I made is:
spl_autoload_register(function($className){
if(is_file('libraries/' . $className . '.php')){
echo 'libraries/' . $className . '.php';
require_once 'libraries/'. $className . '.php';
}
});
File structure in the project is available here: https://prnt.sc/gPaVkLZRsPpj
If I comment out the spl_autoload_register method and require all the necessary files one by one, it is working perfectly fine.
require_once 'libraries/Core.php';
require_once 'libraries/Controller.php';
require_once 'libraries/Database.php';
The file in which I'm trying to do the autoload looks like this:
<?php
require_once '../app/autoload.php';
// Init Core.php
$init = new Core();
And the error message I get is:
Fatal error: Uncaught Error: Class "Core" not found in C:\xampp\htdocs\farkops-mvc\public\index.php:5 Stack trace: #0 {main} thrown in C:\xampp\htdocs\farkops-mvc\public\index.php on line 5
I have searched trough the internet, tried other implementations of spl_autoload_register but they all don't work.
Can someone please help me to resolve this issue? :)

So the problem was (as #Lawrence Cherone mentioned in comments), that autoloader was called in context to the current working directory, in which the file that was calling that autoloader was located.
So I made a few changes.
Made an constant APPROOT, that contains link to app folder (the root folder for all core files)
define('APPROOT', dirname(dirname(__FILE__)));
In my case, APPROOT is C:\xampp\htdocs\mvc\app
Used that constant to get the right directory with autoloader:
spl_autoload_register(function($className){
if(is_file(APPROOT . '/libraries/' . $className . '.php')){
require_once APPROOT . '/libraries/' . $className . '.php';
}
});
And now, autoloader can access filer in folders like
C:\xampp\htdocs\mvc\app\libraries\Core.php without any errors.

Related

spl_autoload_extensions does not load classes

This code works fine on my dev machine (Windows) but on the server it fails to load the classes:
set_include_path(get_include_path() . PATH_SEPARATOR . 'class/');
spl_autoload_extensions('.class.php');
spl_autoload_register();
I've checked the include path and that seems OK. I also attempted to include a absolute path thusly:
$application_root = $_SERVER['DOCUMENT_ROOT'];
set_include_path(get_include_path() . PATH_SEPARATOR . $application_root.'/class/');
with much the same result: the class is not loaded;
This however works:
$autoloader = function( $class_name )
{
$application_root = $_SERVER['DOCUMENT_ROOT'];
$filename = $application_root . '/class/' . str_replace( '\\', '/', $class_name) . '.class.php';
require_once $filename;
};
spl_autoload_register( $autoloader );
But is not as elegant.
How do I get spl_autoload_extensions working on my production machine?
Summary
not working;
set_include_path(get_include_path() . PATH_SEPARATOR .getenv('DOCUMENT_ROOT').'/class');
spl_autoload_extensions('.class.php');
$filter = new Filter();
With get_include_path() I do get a complete path ".:/usr/share/pear:/usr/share/php:/home/httpd/vhosts/_hidden_/httpsdocs/class". I get Fatal error: Class 'Filter' not found.
working:
include getenv('DOCUMENT_ROOT').'/class/Filter.class.php';
$filter = new Filter();
Solved
What hinted me was the case-insensitivity on Windows OS (the file system is btw.) where linux does not ignore case.
The documentation on php.net is sometimes particularly unclear or incomplete. What it didn't say is that it does a strtolower on the generated file (or even path) name.
I had to rename my class files Filter.class.php and YearFilter.class.php to filter.class.php and yearfilter.class.php and so on and so-fort but at the same time keeping the class names abstract class Filter {} and class Yearfilter{} extends Filter` the classes were loaded.
Also I have to disagree with #WinterSilence. The spl_autoload_register() had to be called at least once or the class files were not loaded.
Renaming the class files
The following code worked after renaming all my class file to have lowercase characters only.
<?php
spl_autoload_register();
set_include_path(get_include_path() . PATH_SEPARATOR . 'class/');
spl_autoload_extensions('.class.php');
$f = new Filter();
I know it works by php complaining about Filter being abstract.
Surpassing the build-in autoloader:
Without renaming the class files (which is silly and will cause future bugs). The spl_autoload_extensions has no effect btw.:
<?php
set_include_path(get_include_path() . PATH_SEPARATOR . 'class/');
spl_autoload_extensions('.class.php');
spl_autoload_register(function($class_name) { require_once( $class_name.'.class.php' );},true);
$f = new Filter();
Btw this is already filed as a bug and marked as will not fix as it will break buggy php code that depends on it. Although a patch exists it seem not to have made it in current PHP releases.
EDIT: Btw the main reason of this behavior not being fixed is that whereas everything else is, in php neither class names nor function names are case-sensitive. class FooBar{} equals class FOOBAR{} equals foorbar{}. Having class names case insensitive it makes no sense to have the filename reflect the contents as it can't, really.

Organization of Ajax files for autoloading with php

I want to use the autoloader in my php project and I don't know if my file organization is viable. Right now my folder is structured this way :
-ProjectFolder
index.php
-common
-ajax
ajax_file.php
-classes
MyClass.php
In MyClass.php I have the following line of code namespace common\classes;.
In index.php I have
spl_autoload_register(function ($class_name){
$file = str_replace('\\', '/', $class_name);
require "$file.php";
});
And so I can call in the index.php file the "test" static method by having the following line in my code :
common\classes\MyClass::test();
But index.php is used get answers from ajax_file.php.
If I just call my "test" method by just adding the same line of code into ajax_file.php it tells me that the class can't be found. I guess that it's because it's loaded independently from what's going on in index.php.
I don't know how I can access MyClass from ajax_file.php and I'm not even sure it's possible since I've read some things that seem to indicate it's not possible to "go back" using "../" with the autoloader.
Could you tell me what's the good way do this ?
You have to make sure that your autoloader uses absolute and not relative paths.
This involves defining a base directory for the root namespace corresponding to projectFolder.
In index.php:
spl_autoload_register(function ($class_name) {
$file = __DIR__ . '/' . str_replace('\\', '/', $class_name);
require "$file.php";
});
You have some examples of autoloader on php-fig to comply with the standard (PSR-4).
Note that the ajax_file.php file must explicitly include the autoloader (and therefore index.php)

Autoloading Namespaced Classes

I have searched high and low for an answer and tried every example, but this still fails to find my classes. Why do I keep getting Fatal error: Class 'ProjectMorpheus\model\Database' not found in C:\Portables\xampp\htdocs\ProjectMorpheus\config\config.php on line 23
/ProjectMorpheus
/model
Database.class.php
/config
config.php
So my Database class has a namespace like this:
namespace ProjectMorpheus\model;
class Database { ... }
Finally, my config.php has a function autoloader function (Note: __SITE_PATH = 'C:\Portables\xampp\htdocs\ProjectMorpheus\'):
/*** auto load model classes ***/
function __autoload($class){
$parts = explode('\\', $class);
include __SITE_PATH . 'model/' . end($parts) . '.class.php';
}
$dbh = \ProjectMorpheus\model\Database::getInstance($dsn, $username, $password);
Using spl_autoloader appears to work, but why? My only guess is that $class is not the same in both instances. My spl_function looks like:
spl_autoload_register(function($class){
$parts = explode('\\', $class);
include __SITE_PATH . 'model/' . end($parts) . '.class.php';
});
Why don't you use PSR-0 or PSR-4 autoloader standards?
They even have ready-to-use autoloader class on GitHub As long as you will follow the rules, you won't have any issues and your code will be PSR.
Although I wouldn't recommend but if you would like to insist using the code above for autoloading classes (only in models folder) then try to dump what is the value of __SITE_PATH . 'model/' . end($parts) . '.class.php'; and check if you can access it. You can even try to copy and paste the path to your file explorer to see if the location is reachable and file exists in that directory.
P.S. I tried to add this as a comment but I couldn't due to low rep. points (being new around here and all).

Odd PHP Class autoloader Behavior - PEAR Related

I have a strange problem I can't figure out. I'm using PEAR to send mail from a PHP page. The Send_Mail class is working (sending mail using SMTP), but I'm getting this strange warning associated with my autoloader.
Warning: include(classes/LOGIN.php)
[<a href='function.include'>function.include</a>]:
failed to open stream: No such file or directory in
C:\xampp\htdocs\mysite\initialize.php on line 46`
In my initialize.php file, I have this:
function autoloader($class) {
include 'classes/' . $class . '.php';
}
spl_autoload_register('autoloader');
And in my header.php file I am loading several PHP classes for the site:
// autoload PHP classes for site
autoloader('Navigation');
autoloader('Validation');
The error referes to a LOGIN class which I don't have. But I searched my entire site folder, including php and found these two lines in C:\xampp\php\PEAR\Net\SMTP.php:
/* These standard authentication methods are always available. */
$this->setAuthMethod('LOGIN', array($this, '_authLogin'), false);
$this->setAuthMethod('PLAIN', array($this, '_authPlain'), false);
When I comment out the line containing LOGIN I get the same warning but for PLAIN and when I comment out both lines, the warnings go away (but then SMTP authentication fails).
Why is this happening?
UPDATE
Here is my new autoloader:
function autoloader($class) {
if (file_exists('classes' . $class . '.php')) {
include 'classes' . $class . '.php';
}
}
When I echo 'classes' . $class . '.php', though, I get this:
classes/.php
And then if I change it back to not use the file_exists it works, but the echo still shows classes/.php
I'm not sure what version of Net_SMTP you're on, but the setAuthMethod function takes as a parameter various different types of structures - method names, classes, objects, callables, etc.
Since PHP is dynamically typed, SMTP.php in Net_SMTP has to do a lot of checking on that object in order to determine what type of object it is. As part of that, it tries to determine if 'LOGIN' is a class name, which is invoking your autoloader.
The solution is to perform a file_exists in your autoloader before trying the include, but of course if your include path is complex in any way you're basically setting yourself up for headaches. Anyone who has dealt with writing a comprehensive autoloader knows your pain.
I reverted back to a simple autoloader and things seem to be working fine:
function autoloader($class) {
include 'classes/' . $class . '.php';
}
spl_autoload_register('autoloader');
Thanks for suggestions.

set_include_path Fatal error: Class 'MyClass' not found in file

I'm trying to include a custom path to a certain file using php's set_include_path. Here's the code:
file.php
<?php
$path = 'classes/';
set_include_path(get_include_path() . PATH_SEPARATOR . $path);
$obj = new MyClass();
$obj->methodCall();
?>
Here's my root directory structure
www
|_webapp
|_classes
|_MyClass.php
|_nbproject
|_file.php
All I get when I execute the script is this error message: Fatal error: Class 'MyClass' not found in C:\wamp\www\webapp\file.php. I have tried including the file using require and it works but I have hit a wall with set_include_path. Does anybody know what I can do about this?
Thanks
You're adding a relative path to the global include path. Is that what you intended?
You are possibly not including the file where class MyClass is defined. set_include_path() allows to omit the path in the require_once statement, not to omit the statement itself.
I have the impression that the tool you have in mind is class autoloader.
You choose include method like this format include 'path/filename.php'

Categories