I'm not a PHP expert; am trying to use this TextRank Library to help with a project.
I seem to be running into a bizarre issue: even after adding the autoload function, executing on the command line still results in "class not found" error. So here's the layout:
Code that calls the other classes (the "main" code):
echo realpath (__DIR__);
function __autoload($class_name) {
if(file_exists(__DIR__ . "/lib/TextRank/" . $class_name . '.php')) {
require_once(__DIR__ . "/lib/TextRank/" . $class_name . '.php');
} else {
throw new Exception("Unable to load $class_name.");
}
}
$config = new Config;
$textrank = new TextRank($config);
$keywords = $textrank->getKeywords("The only asynchronous, one-on-four game in Nintendo’s booth came from the “Wait, they’re still making that?” franchise that is Mario Party, and its buried presence didn’t bode well. Thankfully, Mario Party 10’s demo didn’t waste time with the series’ slowest crawl-around-a-board-game moments, instead jumping straight into four mini-games.");
var_dump($keywords);
Here's my directory structure:
/test.php (the above file)
/lib
/lib/TextRank (contains all the classes referenced by the above code
/lib/TextRank/Config.php
Yet, I still get:
Fatal error: Class 'Config' not found in /path/to/test.php
This means that:
The autoload is working, as no exceptions were thrown.
But somehow, PHP still isn't finding the required classes??
Does this have anything to do with the namespace conventions used in the classes, such as:
(in /lib/TextRank/Config.php)
namespace crodas\TextRank;
class Config
{
....
Yes it does. You need to do
$config = new crodas\TextRank\Config();
But that will not get catched by your autoloader. You need to look for an PSR-0 compatible autoloader.
Related
Recently I decided to upgrade some projects from my own (...) autoloader solution to a Composer PSR-4 autoloader. My code already followed PSR-4 so, no big deal there.
On a specific case, I had the following code:
public static function isAutoLoadable($className)
{
$className = ltrim($className, "\\");
$file = $GLOBALS["Path"] . "/src/" . str_replace("\\", "/", $className) . ".php";
if (false !== stream_resolve_include_path($file))
return $file;
return false;
}
It allowed me to check whatever a given class name could be loaded, without actually trying to load it and result on a PHP Class * not found error.
Use case:
I'm currently using it to replace controllers that by some reason couldn't be found with a generic error one, avoiding an App crash and just telling the user something went wrong... then extra internal logging is done.
A function would be good since I can call it before trying to load a controller... I don't want this behavior to spread to any other classes on the app
So my question is: Is there a equivalent way to check if Composer is able to autoload some class without forcing it to load it and cause an error? -- So I can take further actions in case the class wasn't found?
How smart is spl_autoload_register? Does it know to "look ahead" for the class definition in other files before trying to include?
When I run my index.php page I'm seeing
Fatal error: Class 'input\input' not found in /var/www/php/classes/input/date.php on line 4
index.php runs the following (after this block it creates an object from one of the classes, if I uncomment the one line everything works perfectly)
function my_autoloader() {
//include_once "/var/www/php/classes/input/input.php"; //if this is uncommented, it fixes the problem, but I'm not sure why
foreach (glob("/var/www/php/classes/*/*.php") as $filename)
{
require_once $filename;
}
}
spl_autoload_register('my_autoloader');
is my syntax wrong? is spl_autoload_register supposed to function this way? many other files in these folders depend on eachother and the autoloader seems to "figure it out". I'm not sure why it is suddenly hung up on the "input" class in particular
You're using the autoloader in a wrong way. It is only supposed to load the classes you need for a specific request, not the whole folder.
Read more about autoloading classes properly with some good examples: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
You are using it wrongly.
The autoload is used for autoloading only the given class name on the 1st argument of callback, not for loading all classes like you're doing.
For example:
spl_autoload_register(function ($class) {
// ...
$class = stream_resolve_include_path(sprintf("%s.php", $class));
if ($class !== false) {
require $class
}
});
$class will contains the class to load it, so, you can use it to find the file containing this class at your filesystem.
I am trying to load a class in order for a PHP script that I wrote, with help of the classes' documentation, to work.
Since my server is running PHP 5.3, the documentation recommended loading the class like this:
spl_autoload_register(function($class){
if (file_exists('/webgit/webroot/home/myUsername/www/elastica/lib/' . $class . '.php')) {
echo " found \n ";
require_once('/webgit/webroot/home/myUsername/www/elastica/lib/' . $class . '.php');
}
else {
echo " not found! ";
}
});
The only things that are different are that I included echo's in the suite of the if and else.
Also myUsername is actually my username in the file-system path on the server.
Then, it ( the documentation ) suggests that I make a new instance of the class like so:
$elasticaClient = new \Elastica\Client();
However, I am getting an error that the class is not found. Here is exactly what is printed including the error and the suite of my if-else:
not found! Fatal error: Class 'Elastica\Client' not found in /webgit/webroot/home/myUsername/www/elastica/index.php on line 17
line 17 is the line where I try to make an instance of the class.
now, index.php is where the above code is and it is located, on my server, in /webgit/webroot/home/myUsername/www/elastica/
and all the class files are in /webgit/webroot/home/myUsername/www/elastica/lib/
so, I don't understand why it is not able to find / load the class.
I would greatly appreciate any help in solving this!
not found! - it's mean that the file was not found. File, not class.
Variable $class contains full class name with namespaces Elastica\Client. Are you sure that you have /webgit/webroot/home/myUsername/www/elastica/lib/Elastica\Client.php file?
Check How do I use PHP namespaces with autoload? and learn about PSR-0.
Redacted due to excessive wrongness. Mike has a link in the comments worth preserving, however.
I'm a bit new to OOP and I'm working on a 'framework' for my own application. I have my own autoload function which looks like below.. as well as an exception handling object. I won't be using any 3rd party plugins (at least I don't think).
First question: Should I bother with exception handling in my autoload or am I just overdoing things?
Second question: My exceptionHandler class is a public function...since it's something that will be used by many other applications is this the right? Thank you.
Thanks..any input is greatly appreciated.
function __autoload( $class ){
// Define filename pattern to include
$filename = $_SERVER['DOCUMENT_ROOT'] . '/../app/core/models/' . $class . '.class.php';
// Require class if it exists
try {
if ( is_readable( $filename ) ) {
require_once ( $filename );
}
else {
throw new Exception( "Class filename doesn't exist or isn't named correctly: $filename" );
}
}
catch ( Exception $e ) {
// Send to exceptionHandler Class for logging/handling.
$err = new exceptionHandler( $e, 3 );
}
}
Regarding your first question: No, you shouldn't.
First reason: You should always be able to chain multiple autoloaders (see spl_autoload_register), so if one autoloader fails, a second one might be able to load that class. Because of this, your autoloader should not throw any errors unless you know exactly what you're doing.
Second reason: If all autoloading attempts fail, php will trigger an error anyway. Log your php errors properly and you won't need to log this in your autoloader.
Third reason: Your autoloader will be a piece of code that will be executed a lot. You don't want a try/catch block here.
Apart from that: What happens, if autoloading your exceptionHandler fails...?
Any autoload function is really not meant to throw exceptions, because it's not clear where that exception should rise and you would have to either wrap the entire code in a try catch block or define a exception handler.
You should trigger an error via trigger_error or even better let PHP tells you what's the class that is not able to load in the real line where it happens (therefore just ignoring files that doesn't exists).
Also you shouldn't use __autoload but spl_autoload_register.
Thank you for the feedback Jeffrey and Alexander. You guys got me thinking.. I ended up removing my home grown autoloader for an easier (and faster?) method...
In my config file I added the include path for my core application classes as well as the module classes:
set_include_path( get_include_path() . PATH_SEPARATOR . APPLICATION_ROOT . 'core' . DIRECTORY_SEPARATOR . PATH_SEPARATOR . APPLICATION_ROOT . 'module' . DIRECTORY_SEPARATOR );
spl_autoload_extensions( '.class.php' );
spl_autoload_register();
So far it works :)
I have a strange problem I can't figure out. I'm using PEAR to send mail from a PHP page. The Send_Mail class is working (sending mail using SMTP), but I'm getting this strange warning associated with my autoloader.
Warning: include(classes/LOGIN.php)
[<a href='function.include'>function.include</a>]:
failed to open stream: No such file or directory in
C:\xampp\htdocs\mysite\initialize.php on line 46`
In my initialize.php file, I have this:
function autoloader($class) {
include 'classes/' . $class . '.php';
}
spl_autoload_register('autoloader');
And in my header.php file I am loading several PHP classes for the site:
// autoload PHP classes for site
autoloader('Navigation');
autoloader('Validation');
The error referes to a LOGIN class which I don't have. But I searched my entire site folder, including php and found these two lines in C:\xampp\php\PEAR\Net\SMTP.php:
/* These standard authentication methods are always available. */
$this->setAuthMethod('LOGIN', array($this, '_authLogin'), false);
$this->setAuthMethod('PLAIN', array($this, '_authPlain'), false);
When I comment out the line containing LOGIN I get the same warning but for PLAIN and when I comment out both lines, the warnings go away (but then SMTP authentication fails).
Why is this happening?
UPDATE
Here is my new autoloader:
function autoloader($class) {
if (file_exists('classes' . $class . '.php')) {
include 'classes' . $class . '.php';
}
}
When I echo 'classes' . $class . '.php', though, I get this:
classes/.php
And then if I change it back to not use the file_exists it works, but the echo still shows classes/.php
I'm not sure what version of Net_SMTP you're on, but the setAuthMethod function takes as a parameter various different types of structures - method names, classes, objects, callables, etc.
Since PHP is dynamically typed, SMTP.php in Net_SMTP has to do a lot of checking on that object in order to determine what type of object it is. As part of that, it tries to determine if 'LOGIN' is a class name, which is invoking your autoloader.
The solution is to perform a file_exists in your autoloader before trying the include, but of course if your include path is complex in any way you're basically setting yourself up for headaches. Anyone who has dealt with writing a comprehensive autoloader knows your pain.
I reverted back to a simple autoloader and things seem to be working fine:
function autoloader($class) {
include 'classes/' . $class . '.php';
}
spl_autoload_register('autoloader');
Thanks for suggestions.