I'm using the Amazon Payments PHP SDK and the __autoload() is working fine in the browser but when I switch to my CLI scripts it just doesn't seem to be calling the function.
All I'm getting is "PHP Fatal error: Class 'OffAmazonPaymentsService_Client' not found".
I've put debugging into the __autoload() function to echo out the function being called and the file paths and nothing is printed in the terminal, just in the browser.
I've done a print_r(get_defined_functions()); and __autoload() is listed after the require_once() of the file it's in and is not listed before so I know it's getting the right function.
I've also checked the include_path being set and it's in the root of the Amazon Payments source folder which is where it should be so there's no reason why it wouldn't find the class OffAmazonPaymentsService_Client if __autoload() is called.
Can anyone advise why __autoload() isn't working in CLI? I'm not executing with php -a...
I have replaced the __autoload() within the AmazonPayments PHP SDK with spl_autoload_register() and that has worked.
/*
function __autoload($className){
$filePath = str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
$includePaths = explode(PATH_SEPARATOR, get_include_path());
foreach($includePaths as $includePath){
if(file_exists($includePath . DIRECTORY_SEPARATOR . $filePath)){
require_once $filePath;
return;
}
}
}
*/
spl_autoload_register(function($className){
$filePath = str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
$includePaths = explode(PATH_SEPARATOR, get_include_path());
foreach($includePaths as $includePath){
if(file_exists($includePath . DIRECTORY_SEPARATOR . $filePath)){
require_once $filePath;
return;
}
}
});
Related
I was just going through the code of PhileCMS and came across the following lines of code:
if (Registry::isRegistered('Phile_Settings')) {
$config = Registry::get('Phile_Settings');
if (!empty($config['base_url'])) {
return $config['base_url'];
}
}
The file can be seen HERE
How come the static method of class Registry can be used here, when the file is not included or required at all? Is there some kind of auto loading going on in the backend that can't be seen? If so, what is this new kind of auto loading mechanism that has emerged?
Read more about of classes autoloading in PHP: http://php.net/manual/en/language.oop5.autoload.php
In PhileCMS the classes autoloading is confugired in the Phile\Bootstrap::initializeAutoloader() method (copy-paste of method body from the github for convinience):
spl_autoload_extensions(".php");
// load phile core
spl_autoload_register(function ($className) {
$fileName = LIB_DIR . str_replace("\\", DIRECTORY_SEPARATOR, $className) . '.php';
if (file_exists($fileName)) {
require_once $fileName;
}
});
// load phile plugins
spl_autoload_register('\Phile\Plugin\PluginRepository::autoload');
require(LIB_DIR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php');
https://github.com/PhileCMS/Phile/blob/master/lib/Phile/Bootstrap.php#L93
Can you help me connect my php files from different folders..
I have a main folder sample then inside it I have 2 folders naming 0lib and Portal.
Inside the folder 0lib there is folder amazon and inside it there are folders Mock, Model, Samples and some php files like Client.php , Model.php
Inside the folder Portal I have the productFeed.php
I already connect those files using include() and require(). I also use autoload Class... They seems ok but when I run it the error says...
Fatal error: Class 'amazon_Client' not found in /var/www/html/sample/0lib/amazon/Samples/SubmitFeedSample.php on line 68
The SubmitFeedSample.php is inside the folder 0lib->amazon->Samples->SubmitFeedSample.php
Here is my autoload Class codes:
function __autoload($className){
$filePath = str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
$includePaths = explode(PATH_SEPARATOR, get_include_path());
foreach($includePaths as $includePath){
if(file_exists($includePath . DIRECTORY_SEPARATOR . $filePath)){
require_once $filePath;
return;
}
}
}
I think the auto load is the problem here.
I got your function to work as is by making one change:
function __autoload($className){
$filePath = str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
$includePaths = explode(PATH_SEPARATOR, get_include_path());
foreach($includePaths as $includePath){
// Assign the compiled file path here
if(file_exists($classdir = $includePath . DIRECTORY_SEPARATOR . $filePath)){
// Don't use $filePath but rather newly assigned $classdir
require_once($classdir);
return;
}
}
}
EDIT:
The function works, but I think you are missing the relative (or absolute) path. Try creating a config.php file that you can include on all your pages that will set the root path:
root/config.php
define("ROOTDIR",__DIR__);
spl_autoload_register('__autoload');
root/some/document.php
include_once(__DIR__.'/../config.php');
$test = new test_Test();
function.__autoload()
function __autoload($className)
{
$filePath = str_replace('_',"/",$className).'.php';
// This would yield something like:
// /data/19/2/133/150/2948313/user/3268049/htdocs/mydomain/test/Test.php
$classdir = ROOTDIR."/".$filePath;
if(file_exists($classdir)) {
require_once($classdir);
return;
}
}
test_Test Class:
This class would need to be here: ROOTDIR.'/test/Test.php'
I'm writing simple PHP application which is using Swift Mailer library. My app doesn't use namespaces nor composer.
However, after requiring swift_required.php my (model) classes are not found (Fatal error: Class 'Format' not found is thrown by PHP interpret).
Autolading
define("_DOCUMENT_ROOT", str_replace("//", "/", $_SERVER['DOCUMENT_ROOT'] . "/"));
function __autoload($class_name) {
$file_name = $class_name . '.php';
$include_foleder = array("php/model/", "templates/","cron/crons_tasks/");
foreach ($include_foleder as $folder) {
$abs_path = _DOCUMENT_ROOT . $folder . $file_name;
if (file_exists($abs_path)) {
require_once $abs_path;
}
}
}
Problematic part of function
$bar = Format::bar($foo); //works fine
require_once _DOCUMENT_ROOT . "php/lib/swiftmailer-master/lib/swift_required.php"; //works fine
$bar = Format::bar($foo); //Class not found
Class Format is my custom class, located in _DOCUMENT_ROOT . php/model/Format.php. Also other custom classes (from model folder) after requiring Swift Mailer are not found.
So I guessing that my former autoload is somehow overridden by Swift Mailer, is this possible?
Thank you.
Instead of __autoload(), you should use spl_autoload_register.
If there must be multiple autoload functions, spl_autoload_register()
allows for this. It effectively creates a queue of autoload functions,
and runs through each of them in the order they are defined. By
contrast, __autoload() may only be defined once.
http://php.net/manual/en/function.spl-autoload-register.php
define("_DOCUMENT_ROOT", str_replace("//", "/", $_SERVER['DOCUMENT_ROOT'] . "/"));
spl_autoload_register(function($class_name) {
$file_name = $class_name . '.php';
$include_folder = array("php/model/", "templates/","cron/crons_tasks/");
foreach ($include_folder as $folder) {
$abs_path = _DOCUMENT_ROOT . $folder . $file_name;
if (file_exists($abs_path)) {
require_once $abs_path;
}
}
});
I made a simple autoloader using spl_autoloader_register function, it works fine on my virtual server, but in the server I only got "Fatal Error: Class 'X' not found". Im running it on a mac with PHP 5.4, but it also works in windows/ubuntu with 5.3 version, which is the same as my physic server. I don't have SSH access to it. Here is my autoload code:
class Load
{
public static function autoload($class)
{
$class = strtolower($class);
$lib = $_SERVER['DOCUMENT_ROOT'] . BASENAME . "/libs/{$class}.php";
$model = $_SERVER['DOCUMENT_ROOT'] . BASENAME . "/models/{$class}.class.php";
$controller = $_SERVER['DOCUMENT_ROOT'] . BASENAME . "/controllers/{$class}.php";
if(is_readable($lib)){
require_once $lib;
}elseif (is_readable($model)) {
require_once $model;
}elseif (is_readable($controller)){
require_once $controller;
}
}
}
spl_autoload_register("Load::autoload");
I always used spl for local apps, but its the first time I'm trying it on the server.
Any advice for better practices will be helpful.
Thanks
A good practice can be to add your own include path. Then you can disclaim $_SERVER['DOCUMENT_ROOT'].
For example..
// Define path to library
define('MY_LIBRARY_PATH', realpath(dirname(__FILE__) . '/../insert_path_here_relativly'));
// Ensure library is on include_path
set_include_path(
get_include_path() . PATH_SEPARATOR . MY_LIBRARY_PATH
);
Then your autoloader..
class Load
{
public static function autoload($class)
{
$class = strtolower($class);
$lib = MY_LIBRARY_PATH . "/libs/{$class}.php";
$model = MY_LIBRARY_PATH . "/models/{$class}.class.php";
$controller = MY_LIBRARY_PATH . "/controllers/{$class}.php";
if(is_readable($lib)){
require_once $lib;
}elseif (is_readable($model)) {
require_once $model;
}elseif (is_readable($controller)){
require_once $controller;
}
}
}
spl_autoload_register("Load::autoload");
I have a problem with my autoloader:
public function loadClass($className) {
$file = str_replace(array('_', '\\'), '/', $className) . '.php';
include_once $file;
}
As you can see, it's quite simple. I just deduce the filename of the class and try to include it. I have a problem though; I get an exception when trying to load a non-existing class (because I have an error handler which throws exceptions). This is inconvenient, because it's also fired when you use class_exists() on a non-existing class. You don't want an exception there, just a "false" returned.
I fixed this earlier by putting an # before the include (supressing all errors). The big drawback with this, though, is that any parser/compiler errors (that are fatal) in this include won't show up (not even in the logs), resulting in a hard to find bug.
What would be the best way to solve both problems at once? The easiest way would be to include something like this in the autoloader (pseudocode):
foreach (path in the include_path) {
if (is_readable(the path + the class name)) readable = true;
}
if (!readable) return;
But I worry about the performance there. Would it hurt a lot?
(Solved) Made it like this:
public function loadClass($className) {
$file = str_replace(array('_', '\\'), '/', $className) . '.php';
$paths = explode(PATH_SEPARATOR, get_include_path());
foreach ($paths as $path) {
if (is_readable($path . '/' . $file)) {
include_once $file;
return;
}
}
}
It will only get called once per class, so performance shouldn't be a problem.
public function loadClass($className) {
$file = str_replace(array('_', '\\'), '/', $className) . '.php';
if(is_readable($file))
include_once $file;
}
is_readable won't make a huge performance difference.
class_exists() has a second parameter autoload which, when set to FALSE, won't trigger the autoloader for a nonexistant class.
(Solved) Made it like this:
public function loadClass($className) {
$file = str_replace(array('_', '\\'), '/', $className) . '.php';
$paths = explode(PATH_SEPARATOR, get_include_path());
foreach ($paths as $path) {
if (is_readable($path . '/' . $file)) {
include_once $file;
return;
}
}
}