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.
Related
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');
I have a project. I need to get the contents of a file in a package. I could do it the hard way:
file_get_contents('../../vendor/{vendor}/{package}/src/
{directory}/{sub-directory}/class.php');
Or, I could do it the "easy way," which I'm pretty sure is impossible.
namespace MyVendor\MyProject;
use TheirVendor\TheirPackage\TheirClass;
class MyObject
{
public function myFunction()
{
return file_get_contents(TheirClass);
}
}
Is this (or something like it) possible?
You can get the file name of where a class is declared using a ReflectionClass instance and its getFileName() method:
$reflector = new ReflectionClass(\Vendor\Package\Class::class);
echo $reflector->getFileName();
You could use the __NAMESPACE__ global and then replace the backslash with the proper directory separator, then use the __FILE__ global to append the filename
$ns = str_replace( __NAMESPACE__, DIRECTORY_SEPARATOR, '\\' );
$path = $ns.DIRECTORY_SEPARATOR.__FILE__;
and then do what you want with it.
Trying to understand how namespaces and autoload works on PHP
Server.php located at core/server.php
namespace core\server
{
class Main
{
public function getTopic()
{
$get_params = $_GET;
if (empty($get_params)) $get_params = ['subtopic' => 'test'];
return $get_params;
}
}
}
and Index.php
spl_autoload_register();
use core\server as subtopic;
$test = new subtopic\Main();
var_dump($test);
It cant load the class core/server/Main
Autoload doesn't work that way.
First I will explain how autoloaders works.
spl_autoload_register() is a function to register a function you have in your code to server as an autoloader, the standard function would be:
define('APP_PATH','/path/to/your/dir');
function auto_load($class)
{
if(file_exists(APP_PATH.$class.'.php'))
{
include_once APP_PATH.$class.'.php';
}
}
spl_autoload_register('auto_load');
The constant APP_PATH would be the path to your directory where your code lives.
As you noticed it the param that is passed to spl_autoload_register is the name of my function, this register the function so when a class is instanciated it runs that function.
Now an effective way to use autoloaders and namespaces would be the following:
file - /autoloader.php
define('APP_PATH','/path/to/your/dir');
define('DS', DIRECTORY_SEPARATOR);
function auto_load($class)
{
$class = str_replace('\\', DS, $class);
if(file_exists(APP_PATH.$class.'.php'))
{
include_once APP_PATH.$class.'.php';
}
}
spl_autoload_register('auto_load');
file - /index.php
include 'autoloader.php';
$tree = new Libs\Tree();
$apple_tree = new Libs\Tree\AppleTree();
file - /Libs/Tree.php
namespace Libs;
class Tree
{
public function __construct()
{
echo 'Builded '.__CLASS__;
}
}
file - /Libs/Tree/AppleTree.php
namespace Libs\Tree;
class AppleTree
{
public function __construct()
{
echo 'Builded '.__CLASS__;
}
}
I'm using namespaces and autoload to load my functions in a nicely way, you can use namespace to describe in what dir your class resides and uses the autoloader magic to load it without any problems.
Note: I used the constant 'DS', because in *nix it uses '/' and in Windows it uses '\', with DIRECTORY_SEPARATOR we don't have to worry where the code is going to run, because it will be "path-compatible"
I was going through the __autoload feature that PHP provides.
However this is the index.php I have:-
define('app_path', realpath('../'));
$paths = array(
app_path, get_include_path());
set_include_path(implode(PATH_SEPARATOR, $paths));
function __autoload($classname)
{
$filename = str_replace('\\', '/', $classname.'.php');
require_once $filename;
}
use \engine\controllers as Controllers;
$data = new Controllers\base(); // This one is line no. 25 (Here is error)
echo $data->mind('Hi');
And this one as my base.php:-
namespace controllers;
class base {
public function __construct() {
echo __CLASS__ . '<br/>';
echo __NAMESPACE__;
}
public function mind($myname)
{
echo $myname;
}
}
and throws this error:
My directory structure is as follows:
app -> engine -> controller -> base.php
app -> index.php
I am not sure whats wrong is happening. I am just learning how to use namespace and __autoload
I also tried spl_autoload_register but did not success. Kindly suggest.
EDIT:1
Also, if i want to replace it with spl_autoload_register how that can be implemented.
Not sure, but worth a try:
In base.php, change to namespace engine\controllers; on line 1.
And in index.php, change to use engine\controllers as Controllers; (remove leading backslash) on line 23.
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