Include_once in Object dont work - php

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');

Related

PHP namespaces, requires and relative paths issue [duplicate]

I am learning advanced PHP standards and trying to implement new and useful methods. Earlier I was using __autoload just to escape including multiple files on each page, but recently I have seen a tip on __autoload manual
spl_autoload_register() provides a more flexible alternative for
autoloading classes. For this reason, using __autoload() is
discouraged and may be deprecated or removed in the future.
but I really can't figure out how to implement spl_autoload and spl_autoload_register
spl_autoload_register() allows you to register multiple functions (or static methods from your own Autoload class) that PHP will put into a stack/queue and call sequentially when a "new Class" is declared.
So for example:
spl_autoload_register('myAutoloader');
function myAutoloader($className)
{
$path = '/path/to/class/';
include $path.$className.'.php';
}
//-------------------------------------
$myClass = new MyClass();
In the example above, "MyClass" is the name of the class that you are trying to instantiate, PHP passes this name as a string to spl_autoload_register(), which allows you to pick up the variable and use it to "include" the appropriate class/file. As a result you don't specifically need to include that class via an include/require statement...
Just simply call the class you want to instantiate like in the example above, and since you registered a function (via spl_autoload_register()) of your own that will figure out where all your class are located, PHP will use that function.
The benefit of using spl_autoload_register() is that unlike __autoload() you don't need to implement an autoload function in every file that you create. spl_autoload_register() also allows you to register multiple autoload functions to speed up autoloading and make it even easier.
Example:
spl_autoload_register('MyAutoloader::ClassLoader');
spl_autoload_register('MyAutoloader::LibraryLoader');
spl_autoload_register('MyAutoloader::HelperLoader');
spl_autoload_register('MyAutoloader::DatabaseLoader');
class MyAutoloader
{
public static function ClassLoader($className)
{
//your loading logic here
}
public static function LibraryLoader($className)
{
//your loading logic here
}
With regards to spl_autoload, the manual states:
This function is intended to be used as a default implementation for __autoload(). If nothing else is specified and spl_autoload_register() is called without any parameters then this functions will be used for any later call to __autoload().
In more practical terms, if all your files are located in a single directory and your application uses not only .php files, but custom configuration files with .inc extensions for example, then one strategy you could use would be to add your directory containing all files to PHP's include path (via set_include_path()).
And since you require your configuration files as well, you would use spl_autoload_extensions() to list the extensions that you want PHP to look for.
Example:
set_include_path(get_include_path().PATH_SEPARATOR.'path/to/my/directory/');
spl_autoload_extensions('.php, .inc');
spl_autoload_register();
Since spl_autoload is the default implementation of the __autoload() magic method, PHP will call spl_autoload when you try and instantiate a new class.
Since PHP 5.3, you can use spl_autoload_register() with namespaces, which means that you can organize your project and autoload your php classes without any require or include and without redefining an __autoload() function.
To demonstrate this behaviour, just create a file called index.php :
<?php
spl_autoload_register();
var_dump(new Main\Application);
Then create a folder named Main located right next to the index.php file. Finally, creates a file called Application.php located into Main and paste the following code into it :
<?php namespace Main;
class Application{}
Here is the way I do use Autoload.
In the given example I wanto to load classes form 3 diferent directories.
function namespaceAutoload($rawClass){
$class = str_replace('\\', DIRECTORY_SEPARATOR, $rawClass);
$possiblePaths[] = '..\sys\class\file.php';
$possiblePaths[] = '..\sys\class\lib\file.php';
$possiblePaths[] = '..\sys\class\class.file.inc.php';
foreach ($possiblePaths as $templatePath) {
$path = str_replace(["\\", "file"], [DIRECTORY_SEPARATOR, $class], $templatePath);
if (file_exists($path)) {
require_once "$path";
break;
}
} spl_autoload_register("namespaceAutoload");
I the given example, the PHP will look for the namespace\class in these three directories using these three different filename formats.
Working with OOP in php,
spl_autoload_register() lets you register multiple function, classes, trait etc to your php script.
Heres a use case on /test folder structure
/.htaccess
/index.php
/autoload.php
/controller/test.php
Inside autoload.php file:
spl_autoload_register(function ($classname) {
include_once dirname(__FILE__) . "/" . str_replace("\\", "/", $classname) . '.php';
});
Inside .htaccess
DirectoryIndex index.php
# php_value auto_prepend_file
php_value auto_prepend_file "/xampp/htdocs/test/autoload.php"
Inside controller/test.php
namespace controller;
class test {
public static function sayHello () {
echo "hello";
}
}
Inside index.php
use controller/test;
echo test::sayHello();
The autoload.php can be included or like the example above prepend on all script. It loads the class test and lets you use it directly without having to include the test.php script by pathname.

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.

Dynamic path to spl_autoload

Currently I'm recursively looking through my classes folder in order to find the path to my class in order to include it. The problem is, I have many different classes in various different folders that I would like to include. The code that I've created is messy but it works.
The code below is not the recursive function that I've created but it will work for a defined path within the myAutoloader() function.
Is there any way to pass a path to spl_autoload function in PHP?
spl_autoload_register('myAutoloader');
function myAutoloader($className) {
$path = '/classes';
include $path . $className . '.php';
}
//-------------------------------------
// this one will work, as its path is specified in spl_autoload
$myClass1 = new MyClass1();
//this is located in /classes/other so it wont work
$myClass2 = new MyClass2();
There is no way to pass the path to the callback function specified in spl_autoload_register.
You can only create this awareness inside the function:
function myAutoloader($className) {
$paths = array(
'Class1' => '/subpath',
'Class2' => '/subpath/extra',
);
include $paths[$className] . '/'. $className . '.php';
}
That said, I strongly discourage you folliwing this approach. Instead I really suggest you to:
Let composer create your autoload insted doing this manually.
Invest 10 minutes reading PSR-4 Specifications.
If your class "MyClass1" is stored with filename like "MyClass1.php" you can do:
set_include_path('/classes:/classes/other');
spl_autoload_register();

How to call functions in other files without including them with include?

Without using include_once or any include/require how can I reference functions declared in other php files in the current directory? Just like we use fopen.
Including contents of php files which contain code not in functions can be a clutter. It'd be better if function usage is linked automatically to its definition.
I've also checked How to include() all PHP files from a directory? which requires some code to do it.
I'm not able to find answer of this anywhere in internet may be because of too common search terms for this problem.
The most logical approach would be to use OOP and autoloading.
That way you would only load the classes that you actually use.
Otherwise the accepted answer from the question you linked to, is the way to go.
You can use glob to traverse the directory and then include them:
$phpfiles = glob('mydir/*.php');
foreach($phpfiles as $file)
do_something_with_the_file($file) // why not include_once $file ?
As you are referencing functions in other files, you cannot use the autoloader because the autoloader operates on classes. Autoloading classes would be a much better solution.
If you're keen on using classes and OO vs Procedural, this will include a file by the same name as the class that's being called, and will not include class files in the directory that are not needed.
Called from the root directory of the site/application.
define( "APP_PATH", dirname( __FILE__ ) ."/" );
function my_autoloader($class)
{
include 'core/classes/' . $class . '.class.php';
}
spl_autoload_register('my_autoloader');
Assuming you keep all your classes in a similar directory structure:
site/core/classes
You get the idea.

include path and the __autoload function in php

I am trying to convert several php scripts to use the __autoload function. Right now I can use the include and require functions like this:
require_once('path/to/script.php');
But inside of the __autoload function, I can't use the line above. I have to use this:
require_once('absolute/path/to/script.php');
Why does it seem as though the __autoload function doesn't use the include path I have specified in php.ini?
Don't use __autoload... It has a few drawbacks (including limiting yourself to one per execution). Use instead spl_autoload_register if you're on 5.2+.
So what I typically do, is have a class:
class AutoLoader {
protected static $paths = array(
PATH_TO_LIBRARIES,
);
public static function addPath($path) {
$path = realpath($path);
if ($path) {
self::$paths[] = $path;
}
}
public static function load($class) {
$classPath = $class; // Do whatever logic here
foreach (self::$paths as $path) {
if (is_file($path . $classPath)) {
require_once $path . $classPath;
return;
}
}
}
}
spl_autoload_register(array('AutoLoader', 'load'));
That way, if you add a library set, you can just "add it" to your paths by calling AutoLoader::AddPath($path);. This makes testing with your autoloader a LOT easier (IMHO).
One other note. Don't throw exceptions from the autoload class unless absolutely necessary. The reason is that you can install multiple autoloaders, so if you don't know how to load the file, another one may exist to load it. But if you throw an exception, it'll skip the other one...
Personally, I don't ever like to use relative paths with includes. Especially with multiple include directories (like pear), it makes it very difficult to know exactly which file is being imported when you see require 'foo/bar.php';. I prefer to define the absolute path in the beginning of the file set define('PATH_ROOT', dirname(__FILE__));, and then define all my other useful paths off of that directory (PATH_LIBRARIES, PATH_TEMPLATES, etc...). That way, everything is absolutely defined... And no need to deal with relative paths (like the issue you're having now)...
I suspect your __autoload() function is in a separate file then the code which calls it. The path to the included files will be relative to the file which the __autoload() function declaration resides.
It seems like . is not in your include path. So add it use:
set_include_path('.' . PATH_SEPARATOR . get_include_path());
Now PHP should look relative to the executed scripts directory, too. (Executed script here is something like index.php, not autoload.php.
But why don't use simply use a normal relative path like ./path/to/class.php?
Not sure without seeing the whole set-up. My autoload function is within my global functions file, and looks like this:
function __autoload($class) {
if (file_exists("includes/{$class}.php")) {
require_once("includes/{$class}.php");
}
/**
* Add any additional directories to search in within an else if statement here
*/
else {
// handle error gracefully
}
}
I use a relative path because the script is included in my index.php file and all HTTP requests are passed through it.

Categories