Organization of Ajax files for autoloading with php - 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)

Related

How to check if Autoload loads only used classes?

Uisng spl_autoload_register for auto loading classes on my code. Example:
<?php
spl_autoload_register(function ($class_name) {
include 'my_class1.php';
include 'my_class2.php';
//...
include 'my_classN.php';
});
$obj = new MyClass1();
?>
What if I used just class MyClass1 in my code, does autoload loads all files or just my_class1.php?
Thanks in advance.
EDIT: DO NOT use above code. Now I using #Alex Howansky's code with PSR-4 autoloading specifications.
NOTE: Autoload requires to use namespaces if classes located in subdirectory relatively to basedir (see examples).
With this code, the first time you refer to any class, it will load every class. This will work, but almost certainly isn't what you want. In an autoloader, you usually just want to load only the one source file containing the one class referenced by $class_name. Something like this:
spl_autoload_register(function ($class_name) {
$filename = '/path/to/classes/' . $class_name . '.php';
require_once $filename;
});
This obviously becomes very difficult if your source file names don't match your class names or you otherwise can't determine the source file names based on the class names. This is why you should use PSR-4 naming conventions.
Just as an addition, you can use the PHP function get_declared_classes() which will list all defined classes in the current script.

Include_once in Object dont work

I got a problem with php and OOP.
I tried to create a object and inside the object I tried to load data from mysql.
My files are build like this.
HTML
|_ php
|__ objects
|_ content
In object folder is the object file "Event". The object created in a script in php folder and the whole script is called from a html file in content.
My Problem is, that i use the object from different locations. And the include_once method wont work.
event.php:
<?php
include_once(ROOT.'php/db.inc.php');
class Pb1_event
{
public $ev1_id;
// do something
}
I also tried it with include_once('./../db.inc.php');.
How should I include it ? Is it a good way to include it in this file or should I include it anywhere else ?
Firstly what I would do is use either __DIR__, or better is $_SERVER['DOCUMENT_ROOT'] for absolute pathing. These are constants that will refer to your server web root. Assuming it refers to the root directory you have given to us, you would do:
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/db.inc.php';
But to gain a better understanding, you should echo it and see how your directory paths. Also, for the "best practices" you should use autoloading, you can read more about it here:
http://php.net/manual/en/language.oop5.autoload.php
Define an autoload function and have it call the file you need, for example, if you need a class called DB your function might look something like this:
function __autoload($class) {
if ($class == 'DB') {
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/db.inc.php';
}
}
Use __FILE__ or __DIR__ magic constants:
include_once(dirname(__FILE__) . '/../db.inc.php');
include_once(__DIR__ . '/../db.inc.php');
My suggestion would be to register an autoloader in the beginning of your scripts using spl_autoload_register():
spl_autoload_register(function ($className) {
include 'path/to/php/objects/' . $className . '.php';
});
When you want to instantiate an object, where ever you are, you just need to do:
$myclass = new MyClass();
The autoloader will load the correct class. All you need to think about is to call the files in "objects" the same as your classes. Example:
class Pb1_event {
}
filename: path/to/php/objects/Pb1_event.php
you can try this for your warning:
include_once($_SERVER["DOCUMENT_ROOT"].'/php/db.inc.php');

require_once does not work properly when requiring the file from the classes

I am building a tiny PHP MVC framework and here is my folder structure
/app
/controllers
/models
/views
/templates
/config
/config.php
/core
/Controller.php
/Router.php
/init.php
/index.php
Inside the index.php which is the front controller I have this code to require the init.php from /app/core/init.php
index.php
<?php
require_once 'app/core/init.php'
$Router = new Router();
$Controller = new Controller();
?>
app/core/init.php
<?php
require_once 'Controller.php';
require_once 'Router.php';
?>
The init.php requires every base controller and classe in /core directory including Controller.php and Router.php and here the index.php also instantiates the classes
Every thing works fine at this point as I tested this by creating the constructor in both Controller.php and Router.php so the code in these two files will be like this
app/core/Controller.php
<?php
class Controller {
public function __construct() {
echo 'OK!';
}
}
?>
app/core/Router.php
<?php
class Router {
public function __construct() {
echo 'OK!';
}
}
?>
inside the index.php it echoes OK! as the classes are instantiates correctly but the problem is that when I want to include the config.php which is located in /app/config/config.php from the Controller.php located in /app/core/Controller.php with this code
<?php
class Controller {
public function __construct() {
require_once '../config/config.php';
}
}
?>
Whenever I do this it returns this error
Controller::include(../config/config.php) [controller.include]: failed to open stream: No such file or directory in C:\AppServ\www\myapp\app\core\Controller.php on line 6
and
Controller::include() [function.include]: Failed opening '../config/config.php' for inclusion (include_path='.;C:\php5\pear') in C:\AppServ\www\myapp\app\core\Controller.php on line 6
I think I used the correct location, I am working from /app/core/Controller.php and want to require /app/config/config.php. I go back one directory using ../
Then why can't I require the file?
From my personal experience using relative file paths will at some point lead to headaches. So I usually use go with an absolute path to the file. This also has the advantage of being a tiny bit faster.
Then if you get an inclusion error at some point it is easier to find the error since you have the whole path available.
To be able to make absolute paths I would recommend you to add a constant in your index.php file (the frontcontroller). Something like the following:
define('ROOT_PATH', realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR);
Documentation for the functions define(), realpath() and dirname() here.
This defines a constant called ROOT_PATH that references the directory the index.php file is located in and therefore your root directory. At the same time I have appended a directory separator at the end to make it easier to write paths. To use this you would write.
require_once ROOT_PATH . 'config/config.php';
Bonus info
But if you use this approach in your controller.php class you are making it depend in that constant. To remedy this you can pass the root path as a variable in the constructor.
public function __construct($root) {...
And then use it like the following:
public function __construct($root) {
require_once($root . 'config/config.php');
}
Hope this helps.
I don't know what's going on, but require_once() wouldn't throw an error referring to itself as include(), because those are different functions, plus, if that's the whole code, the error line number doesn't match with your require_once() call line either, because it should be 4. Try restarting your webserver and see if it fix something, otherwise you're probably messing something up
While AnotherGuy already gave a proper solution, I'd like to add that the behavior displayed by PHP is actually really quite weird. I set up a little include tree where script A includes B which includes C (all in seperate directories), but B will only include C if I specify a path relative to A, even though the _FILE__ constant at this point shows the path for B. I guess the calling script referred to in the documentation isn't the script calling this function as I'd expect, but rather the script initially served for the request.
I'll wholeheartedly agree with just not using relatively paths, but after years of PHP tinkering it's nice that it just never ceases to surprise to me.

How to organize require and require once in PHP for class import

I have built a PHP video upload library aimed to be used in different frameworks .
## HERE ##.
But i want to make it optimized like , i dodnt want to include or make\
require or require_once call in class and also i want the configuration class to be available to all class i have at run time ... without explicitly calling or making require once.
How can i do that , most php project use bootstrap class /file to do that , and some body pls help me.
I would suggest to make a way to have an auto_load.php file and this file would contain the files required to include, and then you can include this auto_load.php into the entry point file / class to your library to load all the necessary files for your library to work. It is the same idea as how composer work and it is efficient.
You can take a look into psr-4 standards in loading classes.
http://www.php-fig.org/psr/psr-1/
require_once is the same as require except PHP will check if the file has already been included, and if so, not include (require) it again, refer to http://php.net/manual/en/function.require-once.php
You can create an autoload function . This way you will only load the required library.
A basic autoload function looks like this:
define('PATH_LIBRARY', '/some/path/lib/');
function myautoload($class_name){
// you can do string manipulation to build the filename, for example
$filename = strtolower($class_name);
$filename = str_replace('_', '/', $filename);
$filename = ucwords($filename);
$filepath = PATH_LIBRARY.$filename.'.php';
if (file_exists($filepath))
{
require_once($path);
return true;
}
}
spl_autoload_register('myautoload');
Edit that code has to be added at the beginning of your code (usually in a file included at the top of your index.php ), so all instruction after will benefit of it. You can improve it by checking different directory (for example if the class name starts with "controller", or "model", change the path to the appropriate directory)

Why namespace is passed to spl_autoload_register and how can I get rid of it?

I'm currently doing this but it doesn't look right to me:
spl_autoload_register(function ($class_name){
$class_name = str_replace('MyNameSpace\\', '', $class_name . '.php');
require $class_name;
});
Please advise.
The namespace is passed because it has to be. How else would the autoloader function know the difference between Foo\Bar and Baz\Bar? :-)
Your method looks okay if you're absolutely sure that you won't ever need to load classes with the same names as those found in MyNameSpace. The canonical method to autoloading classes involves using the parts of the namespace as file system structure, so that, for example, foo\bar\Baz can be found at path foo/bar/Baz.php.

Categories