Autoloading with namespaces - php

My structure:
/test/init.php
/test/sub/Info.php
init.php:
<?php
namespace test;
$namespaces = function($path) {
//echo $path; = test\sub\Info
if (preg_match('/\\\\/', $path)) {
$path = str_replace('\\', DIRECTORY_SEPARATOR, $path);
}
//echo $path; = test\sub\Info
if (file_exists("{$path}.php")) {
require_once("{$path}.php");
}
};
spl_autoload_register($namespaces);
$info = new sub\Info();
And Info.php:
<?php
namespace test\sub;
class Info
{
public function __construct()
{
echo 123;
}
}
Why this isn't working?
I use Windows, so why DIRECTORY_SEPARATOR == \?
EDIT:
Sorry, I updated my question. I forgot to paste spl_autoload_register on stackoverflow.

Your autoloader ideally needs to be defined outside of a namespace, at the top level of the directory structure - the way you've got it set up at the moment, it's trying to include the file test/sub/Info.php from within the test directory, rather than from the root (i.e. test/test/sub/Info.php, which doesn't exist)
If you remove the namespace prefix test from both files (so remove it entirely from init.php and just have namespace sub; in sub/Info.php) then it will work correctly. The other option would be to move the autoloader into a file in the root directory, so that the namespaces again match up with the file-system layout.

You are using a relative path, so there are several things that could be wrong... You can see which is the current working directory by doing:
echo getcwd();
You could also try something like this:
$namespaces = function($class) {
$basepath = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR;
$file = $basepath . str_replace('\\', DIRECTORY_SEPARATOR, $class) . ".php";
if (!file_exists($file) || !is_readable($file)) {
return false;
}
require_once($file);
return class_exists($class, false);
};
Variable $basepath could be also a defined constant, or a variable from a config file...

Related

PHP Load every class in a directory

I have coded a PHP script that includes every file in a directory. But im wondering if there is a way to load the classes in the files im including like a autoloader or something?
<?php
define("include_dir", dirname(__FILE__) . '/includes/');
foreach (scandir(include_dir) as $filename)
{
if (is_file(include_dir . '/' . $filename))
{
//its a php file, lets do this!
if (substr($filename, -4) == '.php')
{
include include_dir . $filename;
}
}
}
?>
try this-
function __autoload($class_name) {
include $class_name . '.php';
}
$obj = new MyClass1();
$obj2 = new MyClass2();
the manual -
http://php.net/manual/en/language.oop5.autoload.php

Restrict my spl_autoloader to only load classes in my namespace?

I've just begun using autoloader lazy loading in my app, and I'm running afoul of namespacing. The autoloader is trying to load things like new DateTime() and failing. Is there a trick to making my autoloader spcific to only my own namespaced classes?
Here is the code I have currently. I suspect it is a mess, but I'm not seeing just how to correct it:
<?php namespace RSCRM;
class Autoloader {
static public function loader($className) {
$filename = dirname(__FILE__) .'/'. str_replace("\\", '/', $className) . ".php";
if (file_exists($filename)) {
include_once($filename);
if (class_exists($className)) {
return TRUE;
}
}
return FALSE;
}
}
spl_autoload_register('\RSCRM\Autoloader::loader');
Happy to RTM if someone can point to a solid example.
What I use is actually adapted from the autoloader used to Unit Test a few of the AuraPHP libraries:
<?php
spl_autoload_register(function ($class) {
// a partial filename
$part = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
// directories where we can find classes
$dirs = array(
__DIR__ . DIRECTORY_SEPARATOR . 'src',
__DIR__ . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'src',
__DIR__ . DIRECTORY_SEPARATOR . 'install' . DIRECTORY_SEPARATOR . 'src',
);
// go through the directories to find classes
foreach ($dirs as $dir) {
$file = $dir . DIRECTORY_SEPARATOR . $part;
if (is_readable($file)) {
require $file;
return;
}
}
});
Just make sure the array of '$dirs' values point to the root of your namespaced code.
You can also take a look at the PSR-0 example implementation (http://www.php-fig.org/psr/psr-0/).
You might also want to look an into existing autoloader, like Aura.Autoload or the Symfony ClassLoader Component, although those might be overkill depending on what your requirements are.
I hope this helps.

spl_autoload_register issue while loading class

So I already asked this question here earlier, but the solutions provided didn't work for me.
Here's my setup:
/mylib
/Vendor/Module/MyClass.php
/document_root
index.php
Here's my index.php
<?php
define('CLASSDIR', 'mylib');
define('BASEPATH', #realpath( dirname (__FILE__).'/../').'/'.CLASSDIR);
spl_autoload_register(null, false);
spl_autoload_extensions('.php');
function autoLoader($className){
$className = ltrim($className, '\\');
$fileName = '';
$namespace = '';
if ($lastNsPos = strrpos($className, '\\')) {
echo 'does it come here? nope.';
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= BASEPATH.'/'.str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
require $fileName;
}
spl_autoload_register('autoLoader');
//$obj = new MyClass();
$obj = new \Vendor\Module\MyClass();
$obj::test();
?>
Here's my MyClass.php
<?php
namespace Vendor\Module;
class MyClass{
public function __construct(){
echo 'weird';
}
public function test(){
echo 'strange';
}
}
?>
None of my echo's display anything. Obviously my class is also not loaded. Instead I get this error.
Fatal error: Call to undefined method MyClass::test() in /<documentroot>/index.php on line 29
Please help. I've been stuck on this for quite a while now and the rest of my development is suffering. I tried moving to spl_autoload_register() only because it's the recommended way. Now the lost time is making me regret it.
Your are calling the test() function incorrectly (using static way?).
Call the function with:
$obj = new MyClass();
$obj->test();
If you intend to use static method like MyClass::test(), declare your function in your class as:
public static function test() {
}
Moreover, your autoloader is over-complicated. It can be simplified as:
$class_dir = array(
'/mylib/Vendor/Module/',
// Add more paths here ( or you can build your own $class_dir )
);
function class_loader($class_name) {
global $class_dir;
foreach ($class_dir as $directory) {
if (file_exists($directory . $class_name . '.php')) {
require_once($directory . $class_name . '.php');
return;
}
}
}
spl_autoload_register('class_loader');
3rd edit:
I noticed the path you set is incorrect.
$fileName .= BASEPATH.'/'.str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
It should be:
$filename = BASEPATH .'/' . $filename . str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
As said before, it can be easily debugged by echoing the value of $filename.
F**k yes. Yes, I can take the liberty to swear on a public forum this one time.
A huge shout out to #Shivan Raptor for helping me along the way and not giving up.
There were numerous minor issues in the auto-loader function. But the debugging took me so long for just a simple reason that I couldn't see any echo messages. Only lord and XAMPP knows why. Seemed like XAMPP had somehow cached the class on first run or something and no changes later showed any effect. But creating a new class and class file all of a sudden started showing all my echo including the ones inside autoload. Anyone who has picked up the auto-loader code from the link below, please ensure you look at all the variables' values. It doesn't work "out of the box", if you don't keep everything in the document root. And if you are new to both PSR-0 and concept of auto loading, this can kill at least a sizable portion of your perfectly capable brain cells.
https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
Here's the final index.php that worked for me.
<?php
define('CLASSDIR', 'mylib');
define('BASEPATH', #realpath( dirname (__FILE__).'/../').'/'.CLASSDIR);
spl_autoload_register(null, false);
spl_autoload_extensions('.php');
function autoLoader($className){
$className = ltrim($className, '\\');
$classPath = '';
$namespace = '';
if ($lastNsPos = strrpos($className, '\\')) {
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$classPath = str_replace('\\', DIRECTORY_SEPARATOR, $namespace).DIRECTORY_SEPARATOR;
}
$fileName = BASEPATH.'/'.$classPath.str_replace('_', DIRECTORY_SEPARATOR, $className).'.php';
require $fileName;
}
spl_autoload_register('autoLoader');
$obj = new \Vendor\Module\MyClass();
$obj::test();
?>

Spl_Auto_register not loading class properly

I'm trying to learn about spl_autoload_register().
My index.php is under document root, my MyClass.php is put under document root /MyProject/MyClass/MyClass.php
Here's my index.php
<?php
define('CLASSDIR', 'mylib');
define('BASEPATH', #realpath( dirname (__FILE__).'/../').'/'.CLASSDIR);
spl_autoload_register(null, false);
spl_autoload_extensions('.php');
// PSR-0 provided autoloader.
function autoLoader($className){
$className = ltrim($className, '\\');
$fileName = '';
$namespace = '';
if ($lastNsPos = strrpos($className, '\\')) {
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= BASEPATH.'/'.str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
require $fileName;
}
spl_autoload_register('autoLoader');
$obj = new MyClass();
$obj->test();
?>
Here's my Class: MyClass.php
<?php
namespace MyProject\MyClass;
class MyClass{
public function __contruct(){
echo('weird');
}
function test(){
echo 'issue';
}
}?>
Here's the error:
Fatal error: Call to undefined method MyClass::test() in /path/to/file/index.php on line 26
So, I'm assuming it found the class (since it didn't complain)? But the messages 'weird' and 'issue' are not displayed. Telling me that the constructor didn't fire.
Okay, assuming your class file is located in a seperate folder called classes (example)
Structure like this:
DOCUMENT_ROOT/
->index.php
->classes/
->Myclass/
->Myclass.php
Somewhere on your index.php You'd have something looking like this:
<?php
DEFINE('__BASE', realpath(dirname(__FILE__)));
require_once('load.php');
?>
Now your load.php file should have the __autoload() function in there, looking something like this:
// Auto load function to load all the classes as required
function __autoload($class_name) {
$filename = ucfirst($class_name) . '.php';
$file = __BASE . DIRECTORY_SEPARATOR .'classes/' . ucfirst($class_name) . $filename;
// First file (model) doesnt exist
if (!file_exists($file)) {
return false;
} else {
// include class
require $file;
}
}
EDIT:
If you'd like to do it with spl_autoload_register(), you'd have something similar to this in your load.php
// Auto load function to load all the classes as required
function load_classes($class_name) {
$filename = ucfirst($class_name) . '.php';
$file = __BASE . DIRECTORY_SEPARATOR .'classes/' . ucfirst($class_name) . $filename;
// First file (model) doesnt exist
if (!file_exists($file)) {
return false;
} else {
// include class
require $file;
}
}
spl_autoload_register('load_classes');

Php autoload project

I've a project like this:
Now i want to autoload all the php files in the folder classes and sub folders.
I can do that with this:
$dirs = array(
CMS_ROOT.'/classes',
CMS_ROOT.'/classes/layout',
CMS_ROOT.'/classes/layout/pages'
);
foreach( $array as $dir) {
foreach ( glob( $dir."/*.php" ) as $filename ) {
require_once $filename;
}
}
But i dont like this. For example.
"layout/pages/a.php" extends "layout/pages/b.php"
Now i get an error because a.php was loaded first. How do you people load your project files? Classes?
SOLVED :)
This is my code now:
spl_autoload_register('autoloader');
function autoloader($className) {
$className = str_replace('cms_', '', $className);
$className = str_replace('_', '/', $className);
$file = CLASSES.'/'.$className.'.php';
if( file_exists( $file ) ) {
require_once $file;
}
}
You should try this
<?php
spl_autoload_register('your_autoloader');
function your_autoloader($classname) {
static $dirs = array(
CMS_ROOT.'/classes',
CMS_ROOT.'/classes/layout',
CMS_ROOT.'/classes/layout/pages'
);
foreach ($dirs as $dir) {
if (file_exists($dir . '/'. $classname. '.php')) {
include_once $dir . '/' . $classname . '.php';
}
}
}
After registering your_autoloader with spl_autoload_register() it will be called by the php interpreter every time you access a class that:
Has not already been loaded with require_once() or include_once()
Is not part of the PHP internals

Categories