I have a PHP project structured as:
--root
|--dr1
| |---dr2
| |--testclass.php
|--start.php
|--bootstrap.php
The testclass.php contains:
namespace dr1\dr2;
class testclass {
...
}
The bootstrap.php contains:
define('DIR_SEP', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__) . DIR_SEP);
function __autoload($class)
{
$path = ROOT . str_replace('\\', DIR_SEP, $class);
$file = $path . '.php';
if( is_file($file) ) require_once($file);
}
spl_autoload_extensions('.php');
spl_autoload_register('__autoload');
and The start.php contains:
$class = 'dr1\dr2\testclass.php';
$obj = new $class();
When I run the start.php, I got the message dr1\dr2\testclass.php is not found on start.php on line 5. I could not figure out why. would anybody help. thanks a lot.
The autoloader looks correct, so the problem is the Classname testclass.php. In you source-file it's just testclass without the .php - so if you adjust your $class-variable like that it should work:
$class = 'dr1\dr2\testclass';
$obj = new $class();
To access your class you could do
$class = new testclass();
Related
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.
I have PHP namespaced file
namespace A\B\C
$cls = new foo();
Where is the foo class stored?
OR if exist __autoload() how to control directory mapping to namespace?
Thanks for helping. Im trying to closer understand relation between directories and namespaces. PHP and/or Google doesnt give me any answer.
There is not direct relation between directories and namespaces, except if you use an autoloader.
If you want this code to works :
namespace A\B\C;
$cls = new foo();
You must do this :
namespace A\B\C;
class foo {}
$cls = new foo();
Or do this :
foo.php
namespace \A\B\C;
class foo {}
index.php
require 'foo.php';
$cls = new \A\B\C\foo();
// or
namespace A\B\C;
$cls = new foo();
Now if you want to use autoloader, you can use something like this :
function autoload($class)
{
$class = str_replace('\\', '/', $class);
require_once __DIR__ . '/' . $class . '.php';
}
spl_autoload_register('autoload');
Put this kind of code in top of your index.php and the get a dir arch like this :
A
+ B
| + C
| | + foo.php
Then you just have to do :
$cls = new \A\B\C\foo();
or even :
use \A\B\C\foo;
$cls = new foo();
But anyway, YOU MUST READ MANUAL : Link here
I've set up a simple autoload to understand the principles when working together with namespaces.
test.php:
namespace House;
function __autoload($classname)
{
$parts = explode('\\', $classname);
$class = 'Room/'.end($parts).'.php';
require_once($class);
}
$Toy = new Toy();
echo $Toy->hello();
Room/Toy.php:
namespace House;
class Toy
{
public function hello() { return "HELLO"; }
}
When declaring $Toy I get Fatal error: Class 'House\Toy' not found in test.php on line 18
What have I dont wrong here?
When removing __autoload function and instead just putting in
require_once('Room/Toy.php');
It works!
Your test.php should look like this:
use House\Toy as Toy;
function __autoload($classname)
{
$parts = explode('\\', $classname);
$class = 'Room/'.end($parts).'.php';
require_once($class);
}
$Toy = new Toy();
echo $Toy->hello();
If you are putting namespace House on the top of the file, all functions declared in that file will belong to the namespace House. Meaning __autoload() get's House\__autoload() and will loose it's magic meaning.
Another thing, wouldn't it be better to store the files of the namespace House in a folder named House? (You are currently using Room). If you are doing so, the __autoload() function could be written more generally:
function __autoload($classname)
{
$parts = explode('\\', $classname);
$path = implode('/', $parts) . '.php';
require_once($path);
}
Try using this autoloader instead :) and add the absolute path to directory Room to your include path. Inside Room have another directory called House where Toy.php will be located.
<?php
spl_autoload_register ( function ( $className, $fileExtensions = null ) {
$className = str_replace ( '_', '/', $className );
$className = str_replace ( '\\', '/', $className );
$file = stream_resolve_include_path ( $className . '.php' );
if ( $file !== false ) {
include $file;
return true;
}
return false;
});
so i've started using namespaces and read some docs but I seem to be doing something wrong.
First off is my application structure which is build like this:
root
-dashboard(this is where i want to use the autoloader)
-index.php
--config(includes the autoloader)
--WePack(package)
---src(includes all my classes)
now in the src directory I included the classes with:
namespace WePack\src;
class Someclass(){
}
the content of config.php is:
<?php
// Start de sessie
ob_start();
session_start();
// Locate application path
define('ROOT', dirname(dirname(__FILE__)));
set_include_path(ROOT);
spl_autoload_extensions(".php"); // comma-separated list
spl_autoload_register();
echo get_include_path();
and I use it like this in my index.php
require_once ('config/config.php');
use WePack\src;
$someclass = new Someclass;
this is what the echo get_include_path(); returns:
/home/wepack/public_html/dashboard
which is what I want I guess. but the classes are not loaded and nothing is happening. I'm obviously missing something but I can't seem to figure it out. could you guys take a look at it and explain to me why this isn't working?
The problem here is, that you don't register a callback function with spl_autoload_register(). have a look at the official docs.
To be more flexible, you can write your own class to register and autoload classes like this:
class Autoloader
{
private $baseDir = null;
private function __construct($baseDir = null)
{
if ($baseDir === null) {
$this->baseDir = dirname(__FILE__);
} else {
$this->baseDir = rtrim($baseDir, '');
}
}
public static function register($baseDir = null)
{
//create an instance of the autoloader
$loader = new self($baseDir);
//register your own autoloader, which is contained in this class
spl_autoload_register(array($loader, 'autoload'));
return $loader;
}
private function autoload($class)
{
if ($class[0] === '\\') {
$class = substr($class, 1);
}
//if you want you can check if the autoloader is responsible for a specific namespace
if (strpos($class, 'yourNameSpace') !== 0) {
return;
}
//replace backslashes from the namespace with a normal directory separator
$file = sprintf('%s/%s.php', $this->baseDir, str_replace('\\', DIRECTORY_SEPARATOR, $class));
//include your file
if (is_file($file)) {
require_once($file);
}
}
}
after this you'll register your autoloader like this:
Autoloader::register("/your/path/to/your/libraries");
Isn't this what you mean:
spl_autoload_register(function( $class ) {
include_once ROOT.'/classes/'.$class.'.php';
});
That way you can just call a class like:
$user = new User(); // And loads it from "ROOT"/classes/User.php
I'm looking for a way to load classes into PHP without using hardwired names.
The idea is the script will load a text file with names of 'components'(classes), then load them by the names in the file. For example:
<xml><Classes><class name="myClass"/></Classes></xml>
When the PHP is run, it would need to do something like this:
require_once {myClass}".class.php";
var myclass = new {myClass}();
require_once $class . ".class.php";
$myclass = new $class;
See http://www.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.new.
Your example is almost correct as is. You can just replace {myClass} with $myClass and it should work.
Here's a simple example of how this could be used:
File: myClass.class.php
<?php
class myClass {
public $myVar = 'myText';
}
?>
File: test.php
<?php
$className = "myClass";
require_once $className . ".class.php";
$myInstance = new $className;
echo $myInstance->myVar;
?>
This should output "myText" to the screen, the contents of your dynamically included class property.
Use the ReflectionClass for this.
require_once $class . ".class.php";
$refl = new \ReflectionClass($class);
$params_for_construct = array($param1, param2);
$instance = $refl->newInstanceArgs($params_for_construct);
Why not just use autoloader
spl_autoload_register(function ($class) {
require 'class_folder/' . $class . '.class.php';
});