php - autoload not working with static method - php

I using spl_autoload_register to autoload class like
My Structure
index.php
Module\Autoloader.php
Module\MyClass.php
Test\test.php
in index.php file
require_once ("Module\Autoloader.php");
use Module\MyClass;
include 'Test\test.php';
in Module\Autoloader.php file
class Autoloader {
static public function loader($className) {
$filename = __DIR__."/" . str_replace("\\", '/', $className) . ".php";
echo $filename.'<br>';
if (file_exists($filename)) {
include($filename);
}
}
}
spl_autoload_register('Autoloader::loader');
in Module\MyClass.php file
namespace Module;
class MyClass {
public static function run() {
echo 'run';
}
}
in Test\test.php file
MyClass::run();
But it has error
Fatal error: Uncaught Error: Class 'MyClass' not found in ..\Test\test.php
How to fix that thank

your issue is that you prepend __DIR__
__DIR__ is based on where the file from which it gets called resides:
__DIR__
The directory of the file. If used inside an include, the directory of the included file is returned. This is equivalent to dirname(__FILE__). This directory name does not have a trailing slash unless it is the root directory.
http://php.net/manual/en/language.constants.predefined.php
So because your autoloader routine resides in ./Module/
__DIR__ will not return / when called from index.php but Module, making your finished classpath Module/Module/MyClass.php which obviously can't be found.
Either use another means of prepending the directory, like a predetermined list, use the first part of the namespace (so just ditch the __DIR__) or move the classes to location relative to directory in which your include file resides.

Your autoloader is inside the Module dir so it will apppend an extra "Module" when you try to append "DIR" to the class full name. The file location will be something like this:
../Module/Module/MyClass.php
Try to move your autoloader the same dir as index.php or change it as the following:
<?php
class Autoloader {
static public function loader($className) {
$filename = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR .
str_replace("\\", DIRECTORY_SEPARATOR, $className) . ".php";
if (file_exists($filename)) {
include($filename);
} else {
echo "$filename not found!\n";
}
}
}
spl_autoload_register('Autoloader::loader');

Related

How to open a .json file in a certain namespace

It should be easy to load a file using a namespace, but I cannot seem to generate the url to it. The file is located in the same directory as MyClass, where it is called from.
<?php namespace Mynamespace\Subnamespace;
class MyClass {
public function getFile() {
$fileLocation = 'myfile.json'; // file is located next to this class in Mynamespace\Subnamespace\file.json
return file_get_contents( $fileLocation );
}
}
The closest solution I found is using the method getFileName() in a ReflectionClass of MyClass. But that returns the full url including the class MyClass.php file. And using a regExp on that seems overkill, since there is probably an easier solution.
If a namespace can somehow be converted into a valid url, that should do the trick.
How should file.json be retreived?
You can't use namespaces for JSON files. But since it is in the same directory as the class you should be able to use __DIR__
<?php namespace Mynamespace\Subnamespace;
class MyClass {
public function getFile() {
$fileLocation = 'myfile.json';
return file_get_contents( __DIR__ . PATH_SEPARATOR . $fileLocation );
}
}
The easiest way to do this is with get_class
<?php namespace Mynamespace\Subnamespace;
class MyClass {
public function getFile() {
// Will have backslashes so str_replace if this is a Unix environment
$path = str_replace('\\', '/', get_class($this));
$fileLocation = $path . '/myfile.json'; // Mynamespace/Subnamespace/myfile.json
return file_get_contents( $fileLocation );
}
}
If I understand correctly, just this:
$fileLocation = __NAMESPACE__ . '\myfile.json';
See PHP: namespace keyword and __NAMESPACE__ constant.
But since you state "file is located next to this class in Mynamespace\Subnamespace\file.json" then you can just use the full path to the current file:
$fileLocation = __DIR__ . '\myfile.json'; // or dirname(__FILE__)
See PHP: Magic Constants.

How to use the PSR-4 autoload in my /Classes/ folder?

I've tried multiple PSR-4 loaders, but they either don't work or I can't access the classes from another folder.
My current folder structure:
-Classes
--Config.php
--Session.php
--Frontend (folder)
---Login.php
PSR-4 Autoloader:
I tried to load all classes using the PSR-4 autoload register. I modified it slightly to my folder structure. I've given all classes the namespace Classes, but the ones in the Frotend folder has the namespace Classes\Frontend.
spl_autoload_register(function ($class) {
// project-specific namespace prefix
$prefix = 'Classes\\';
// base directory for the namespace prefix
$base_dir = __DIR__ . '/Classes/';
// does the class use the namespace prefix?
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
// no, move to the next registered autoloader
return;
}
// get the relative class name
$relative_class = substr($class, $len);
// replace the namespace prefix with the base directory, replace namespace
// separators with directory separators in the relative class name, append
// with .php
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
// if the file exists, require it
if (file_exists($file)) {
require $file;
}
});
I'm not sure if this has to do with the autoloader, but I also want to call the class from any file wherever it's located. So if I have a file in
/Frontend/templates/login-page.php
I want to be able to call the class "Classes\Frontend\Login".
Is this possible and how would I do that?
There are mainly two ways to get it working: The first option is to use an absolute server path (starting with a '/'), to set the base directory for your classes in your autoload function:
spl_autoload_register(function ($class) {
$prefix = 'Classes\\';
$base_dir = '/var/www/html/my_project/src/'; // your classes folder
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
return;
}
$relative_class = substr($class, $len);
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
if (file_exists($file)) {
require $file;
}
});
The better solution is, as #FĂ©lix suggested, to stick with the __DIR__ constant to keep things relative to your project folder. Absolute paths are brittle between deployments on different servers. __DIR__ refers to the directory of the file it is used in; in this case it is where you register the autoload function. Starting from this directory, you can navigate to the classes base directory, for example $base_dir = __DIR__ . '/../../src/;
Don't forget to namespace your classes:
namespace Classes;
class Foo
{
public function test()
{
echo 'Hurray';
}
}
Then use classes like this:
$foo = new Classes\Foo();
$foo->test();

Oriented Object PHP autoloader issue

I encounterd a little problem with my classes : they simply do not load through my autoloader.
I get this message error :
Warning:
require(C:\wamp64\www\blog\appAutoloader.php/Table/PostsTable.php):
failed to open stream: No such file or directory in
C:\wamp64\www\blog\app\Autoloader.php on line 23
Fatal error: require(): Failed opening required
'C:\wamp64\www\blog\appAutoloader.php/Table/PostsTable.php'
(include_path='.;C:\php\pear') in
C:\wamp64\www\blog\app\Autoloader.php on line 23
Factory class :
use Core\config;
use Core\Database\MysqlDatabase;
class App {
public $title = "My super site";
private $db_instance;
private static $_instance;
public static function getInstance()
{
if (is_null(self::$_instance))
{
self::$_instance = new App();
}
return self::$_instance;
}
public static function load()
{
session_start();
require ROOT . '/app/Autoloader.php';
App\Autoloader::register();
require ROOT .'/core/Autoloader.php';
Core\Autoloader::register();
}
public function getTable($name)
{
$class_name = '\\App\\Table\\' . ucfirst($name) .'Table';
return new $class_name($this->getDb());
}
public function getDb()
{
$config = Config::getInstance(ROOT . '/config/config.php');
if (is_null($this->db_instance)) {
$this->db_instance = new MysqlDatabase($config->get('db_name'), $config->get('db_user'), $config->get('db_pass'), $config->get('db_host'));
}
return $this->db_instance;
}
}
Namespace App autoloader class :
<?php
namespace App;
class Autoloader {
static function register()
{
spl_autoload_register(array(__CLASS__, 'autoload')); // __CLASS__ load the current class
}
static function autoload($class)
{
if (strpos($class, __NAMESPACE__ .'\\') === 0) {
$class = str_replace(__NAMESPACE__ . '\\', '', $class); // _NAMESPACE_ load the current name_space
$class = str_replace('\\', '/', $class);
require __DIR__ . 'Autoloader.php/' . $class . '.php'; // __DIR__ = the parent folder. Here "app"
}
}
}
Namespace Core autoloader class :
<?php
namespace Core;
class Autoloader {
static function register()
{
spl_autoload_register(array(__CLASS__, 'autoload')); // __CLASS__ load the current class
}
static function autoload($class)
{
if (strpos($class, __NAMESPACE__ .'\\') === 0) {
$class = str_replace(__NAMESPACE__ . '\\', '', $class); // _NAMESPACE_ load the current name_space
$class = str_replace('\\', '/', $class);
require __DIR__ . 'Autoloader.php/' . $class . '.php'; // __DIR__ = the parent folder. Here "app"
}
}
}
Empty PostTable
namespace App\Table;
use Core\Table\Table;
class PostsTable extends Table
{
}
Index page :
define('ROOT', dirname(__DIR__));
require ROOT . '/app/App.php';
App::load();
$app = App::getInstance();
$posts = $app->getTable('Posts');
var_dump($posts->all());
How to make it works please?
AS I said in the comments check this path
require(C:\wamp64\www\blog\appAutoloader.php/Table/PostsTable.php)
Doesn't look right to me
require(C:\wamp64\www\blog\ [appAutoloader.php] /Table/PostsTable.php)
What's that bit doing there....
Also namespace of App is not app for the folder its App because this may work on Windows but you will find it does not work on Linux. Because Linux paths are case sensitive, and windows are not.
Further this makes little to no sense
require __DIR__ . 'Autoloader.php/' . $class . '.php'; // __DIR__ = the parent folder. Here "app"
Require 2 files? Paths don't work that way, not that I am aware of at least.
On top of that your implementation ignores the _ Typically underlines will be part of the class name but are replaced by directory, this allows a shorter namespace. So for example instead of having a namespace like this
Namespace \APP\Table;
class PostsTable ..
You could have a class in the same place Like so
Namespace \APP;
class Table_PostsTable ..
With a shorter namespace but still located in the App/Table/PostsTable.php file. However, that's just how I read the spec for PSR autoloaders.
PRO TIP
Take this path C:\wamp64\www\blog\appAutoloader.php/Table/PostsTable.php open the file browser on you desktop and see if it pulls up the file by pasting it into the navigation bar. It wont, but you can be sure your path is wrong by eliminating the code.

namespace & __autoload

I have a file SQL_config.php:
namespace database;
class SQL_config
{
private $_server="localhost";
private $_user="root";
private $_password="";
private static $_singleton;
private $_connection;
protected function __construct()
{
$this->_connection=mysql_connect($this->_server,$this->_user,$this->_password);
}
public static function getInstance()
{
if(is_null(self::$_singleton))
{
self::$_singleton=new SQL_config();
}
return self::$_singleton;
}
}
and index.php:
//namespace database;
//require_once'SQL_config.php';
function __autoload($class)
{
// convert namespace to full file path
//$class = 'database/' . str_replace('\\', '/', $class) . '.php';
//require_once($class);
require_once $class . '.php';
}
$connection=database\SQL_config::getInstance();
and doesn't work. Warning: require_once(database\SQL_config.php) [function.require-once]: failed to open stream: No such file or directory in C:\wamp\www\Formular_contact\index.php on line 11. For all version I use it give me error
can't somebody help me?
define(CLASS_DIR, "/path_to_your_classes_to_load/");
require_once CLASS_DIR . str_replace('\\', '/', ltrim($className, '\\')) . '.php';
You need to replace "\" with "/" and add a ".php" to the end of the new class name as it will only get the name without the coma and the extension. And locate the class in the correct folder as shown in the path.
function __autoload($className){
$newClassName= str_replace("\\", "/", $className) .".php";
require_once($newClassName);
}
Make sure that you locate the class file in the correct folders such as
./database/SQL_config.php
If your class is in a folder "classes" Try this instead.
function __autoload($className){
$newClassName = "classes/";
$newClassName .= str_replace("\\", "/", $className) .".php";
require_once($newClassName);
}
Make sure that you locate the class file in the correct folders such as
./classes/database/SQL_config.php
In the code that you have presented - the location of your class file in file structure is also important.

How to autoload PHP 5.3 classes?

I am trying to autoload my PHP 5.3 namespaced classes eg.
/JM
Auth.php
User.php
Db/Entity.php
/ ...
I did
namespace KM;
class Autoloader {
public static function registerAutolaod() {
ini_set('include_path', dirname(__FILE__) . PATH_SEPARATOR . ini_get('include_path'));
spl_autoload_register(function ($classname) {
$file = preg_replace('/\\\/', DIRECTORY_SEPARATOR, $classname) . '.php';
echo $file . '<br />';
include ($file);
});
}
}
Problem is sometimes I get classname as User sometimes KM\User how can I fix this?
The $classname you receive in your callback function will be assumed to be local. That's because you have defined your __autoloader within a namespace.
To always get the absolute / fully qualified namespace and class name, declare your autoloader in the global scope. http://www.php.net/manual/en/language.oop5.autoload.php#87985

Categories