Problem:
I have an index.php file which has several composer dependencies.
Inside the index.php file i'm trying to call the static method from the outside class in a different php (let's say auth.php) file like this:
/*creating a class instance*/
$var = new AuthClass();
/*accessing an outside class method*/
$var = AuthClass::checkTime($tokenCode);
The issue is the checkTime method inside the class requires a composer dependency as well, which isn't inherited, although the file is located in the same folder as index.php and index.php is included.
PHP Fatal error: Uncaught Error: Class 'Token' not found
I've tried everything - from adding require_once/include 'index.php' to copying the composer autoload to auth.php outside and inside the AuthClass code, but nothing works, i'm still getting the same error.
Additional code:
index.php
require __DIR__ . '/src/vendor/autoload.php';
$argument1 = $_GET['argument1'];
$tokenCode = $_GET['tokenCode'];
include 'config/database.php';
include 'objects/program1.php';
include 'auth.php';
use ReallySimpleJWT\Token;
use Carbon\Carbon;
$secret = "somesecret";
if (($_SERVER['REQUEST_METHOD']) == "GET") {
if ($_GET['url'] == "bankquery") {
if($tokenCode===NULL){
echo "no correct token provided";
print($results);
} else {
$results = Token::validate($tokenCode, $secret);
if ($results = 1){
$var = new AuthClass();
$var = AuthClass::checkTime($tokenCode);
} else {
echo "no correct token provided";
}
}
} else {
echo "some GET other query";
}
?>
auth.php
// loading composer
require __DIR__ . '/src/vendor/autoload.php';
//loading my index.php file
include 'index.php';
//using composer dependencies
use ReallySimpleJWT\Token;
use Carbon\Carbon;
class AuthClass{
public static function checkTime($tokenCode){
// getting payload from token code by accessing the composer dependency method in a class Token
$received = Token::getPayload($tokenCode);
return $received;
}
}
?>
Need help, guys.
You're using AuthClass before it was defined - try move include 'index.php'; line at the end of the file.
You should also include vendor/autoload.php only once - you don't need to repeat this in every file, just make sure that it is included at the top of the entry file which handles request.
But this is more like a result of design problem. You should define AuthClass in separate file and avoid any additional side effects in it - file should only define class. This is part of PSR-1 rules:
Files SHOULD either declare symbols (classes, functions, constants, etc.)
or cause side-effects (e.g. generate output, change .ini settings, etc.)
but SHOULD NOT do both.
Since you're already using autoloader from Composer it should be relatively easy to register your own autoloading rules, so Composer's autoloader will take care about classes autoloading.
If at this point you're still getting Class 'X' not found, you probably did not installed some dependency or your autoloading rules are incorrect.
The simplest solution would be to include your own code in the composer autoloading.
The composer website tells you how to do it.
You don't need to require the composer files yourself and composer handles everything for you.
The PSR-4 tells you how to namespace your code to use Namespacing.
Related
I am working on an application where i have quite a lot of PHP Classes and i write classes like below
<?php
if(!class_exists('AClass1')){
class AClass1{
}
}
?>
and likewise i have around 400 classes and also i use a php autoloader script
https://github.com/varunsridharan/php-autoloader
Along with a classmap generator
https://github.com/varunsridharan/php-classmap-generator
So what happens is that when i write a condition like below
if(class_exists('AClass1')){
// Some Code To RUN
}
In the above code if the class AClass1 not exists then it autoloads via class_exists function which is good for me
But when i write a code like this in a file called aclass1.php
<?php
if(!class_exists('AClass1')){
class AClass1{
}
}
?>
and if that file is loaded via above if condition then after loading the file it still loops into autoloader instead it just should register the class
so whats the good way to avoid looping into autoloader even if the file inside class source
Never use class_exists when registering a class
use class_exists('CLASSNAME',false) to avoid looping inside autoloader
I wrote a simple test to see if a include loop might exists:
test.php
<?php
// The simpliest autoloader
spl_autoload_register(function ($class) {
include __DIR__ . '/Hello.php';
});
if (class_exists('Hello')) {
$hello = new Hello();
exit('class exists');
} else {
exit('class does not exists');
}
Hello.php
<?php
if (!class_exists('Hello')) {
class Hello {
}
}
I put both these files in the same folder. Then I run:
php test.php
There is no error or loop. It simply prints:
class exists
But frankly, you do not need the class_exists check in your class file at all if you're using an autoloader. The autoloader would only be called if the class is not already exists in the current environment. So unless you would manually include a class file after it is autoloaded, you'll be fine.
If for some strange reason you might have that, use include_once instead of include.
According to the top comment on the PHP page spl_autoload_register( ) :
Good news for PHP 5.3 users with namespaced classes:
When you create a subfolder structure matching the namespaces of the >containing classes, you will never even have to define an autoloader.
<?php
spl_autoload_extensions(".php"); // comma-separated list
spl_autoload_register();
?>
However, when I have the following structure:
* classes/someclass.php
* index.php
Where someclass.php contains the following:
<?php
class someclass {
function __construct( ) {
echo 'It works!';
}
}
?>
and index.php contains:
<?php
spl_autoload_extensions(".php");
spl_autoload_register();
new classes\someclass;
?>
Then I get the following error:
Fatal error: spl_autoload(): Class classes\someclass could not be
loaded
Am I getting this wrong? How can I make this work?
From the comments
This doesn't work either for the class:
<?php
namespace classes;
class someclass {
function __construct( ) {
echo 'It works!';
}
}
?>
In your someclass.php file you must define the namespace at the begginning.
<?php
namespace classes;
TLDR; It works, but:
namespace classes; is missing in classes/someclass.php
set_include_path(__DIR__); is missing in index.php
(spl_autoload_extensions(".php") is not necessary)
Include Path
The SPL autoload implementation is include path based. Using a dot as include path is relative to the working directory (!) which is independent from script file location. __DIR__ names the exact directory that is needed if the classes folder lies next to the index.php file as in the scenario.
Directory Separator mapping
Next the autoloader implementation does map the class namespace separator properly on Unix systems. In case that got lost in the o/p, the PHP source code clearly has this.
Case Sensitivity of File Names
What the source code also shows is that file-names to load are made lowercase. That is, if your file system is case sensitive, the file and directory names must be in lower case.
Refernces:
https://lxr.room11.org/xref/php-src%407.1/ext/spl/php_spl.c#spl_autoload
https://lxr.room11.org/xref/php-src%407.1/ext/spl/php_spl.c#307
PHP - most lightweight psr-0 compliant autoloader
The user, SedaSoft, who had posted the Good news comment you which you refer, had subsequently posted another comment, due to a revision of ideas:
What I said here previously is only true on Windows. The built-in
default autoloader that is registered when you call
spl_autoload_register() without any arguments simply adds the
qualified class name plus the registered file extension (.php) to each
of the include paths and tries to include that file.
Example (on Windows):
include paths:
- "."
- "d:/projects/phplib"
qualified class name to load:
network\http\rest\Resource
Here's what happens:
PHP tries to load
'.\\network\\http\\rest\\Resource.php'
-> file not found
PHP tries to load
'd:/projects/phplib\\network\\http\\rest\\Resource.php'
-> file found and included
Note the slashes and backslashes in the file path. On Windows this
works perfectly, but on a Linux machine, the backslashes won't work
and additionally the file names are case-sensitive.
That's why on Linux the quick-and-easy way would be to convert these
qualified class names to slashes and to lowercase and pass them to the
built-in autoloader like so:
<?php
spl_autoload_register(
function ($pClassName) {
spl_autoload(strtolower(str_replace("\\", "/", $pClassName)));
}
);
?>
But this means, you have to save all your classes with lowercase file
names. Otherwise, if you omit the strtolower call, you have to use the
class names exactly as specified by the file name, which can be
annoying for class names that are defined with non-straightforward
case like e. g. XMLHttpRequest.
I prefer the lowercase approach, because it is easier to use and the
file name conversion can be done automatically on deploying.
Note that this commenter had actually posted an answer here on SO today, containing the above links (along with a short explantation), but it was subsequently deleted, whilst in the review queue - presumably due to its brevity. I have reinstated the commenter's answer, along with the content of the link. Their answer was as follows:
I wrote that comment on php.net some time ago when I was working on a
Windows system. Later, I had to partially revoke what I wrote in that
comment on the very same page in another comment, which also contains
a possible solution to the problem that is the easiest I could think
of (apart from using Composer).
Here is a screenshot of the original answer:
Do not roll your own autoloading, but use composer instead.
Create a composer.json in the root of your project:
{
"autoload": {
"psr-4": {
"classes\\": "classes/"
}
}
}
Install composer, then run
composer dump-autoload
In your index.php, require the autoloader:
require __DIR__ . '/vendor/autoload.php';
For reference, see
https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx
https://getcomposer.org/doc/01-basic-usage.md#autoloading
http://www.php-fig.org/psr/psr-0/
http://www.php-fig.org/psr/psr-4/
Do not use the spl_autoload_extensions () function if the files to load only have the php extension.
In my case, I create a class called autoload .. something similar to this:
<?php
class Autoload
{
private static $_extensions = array(
0 => '.inc',
1 => '.lib.php',
2 => '.class.php',
);
public function __construct()
{
self::set_include_path();
spl_autoload_extensions(implode(',', self::$_extensions));
spl_autoload_register(__CLASS__, 'load_class');
}
public static function set_include_paths()
{
set_include_path(implode(PATH_SEPARATOR, array(
realpath('classes');
realpath('system');
...
get_include_path();,
)));
}
public function load_class($class)
{
if (!empty($class)) {
spl_autoload($class);
}
return false;
}
}
The use of ?> At the end of the file is not necessary.
composer.json:
{
"require": {
"smarty/smarty": "v3.1.17"
}
}
index.php:
define('SMARTY_SPL_AUTOLOAD', 1); // now smarty should use its own autoloader
require_once __DIR__ . "/vendor/autoload.php";
function my_classes_loader($class) {
$path = "{$class}.class.php";
if (file_exists($path)) {
include_once $path;
return true;
}
return false;
}
spl_autoload_register('my_classes_loader');
$smarty = new Smarty();
$smarty->setCompileDir("templates_c");
$smarty->display('main.html');
exit();
If I open it in browser I get
Fatal error: Class 'Smarty_Internal_TemplateCompilerBase' not found in
//smarty-example/vendor/smarty/smarty/distribution/libs/sysplugins/smarty_internal_smartytemplatecompiler.php
on line XX
The file is there. And it has content. And it is accessible / readable for PHP etc.
What am I doing wrong? What is missing?
It is a good idea to only have one point deciding about autoloading, and this should be Composer alone.
Try to put your own autoload function away, use a autoload declaration in your composer.json instead. Unfortunately you are not using either PSR-0 or PSR-4 naming standard, but Composer allows you to use "classmap" in this case. Consider moving all your file names to comply with PSR-0.
And the smarty autoloading should already be done by requiring it via Composer. No need to set that constant.
Last but not least I think your autoload function should not return anything. Especially it should not return false if it cannot find the file it supposes to contain the class, because depending on how the autoload functions are ordered on the stack, your function might get called first for ALL classes, including all Smarty ones. If you return false in these cases, you destroy the working autoload stack by not allowing later functions to load that class.
So all in all it is best to use Composer for all autoloading. The developers did everything to provide the best performing autoload function - your own function probably can only be as fast as theirs, but will probably be slower.
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'm including a PHP class with
require_once($ENGINE."/classUser.php");
but when the code is executed i receive this error:
Fatal error: Class 'User' not found in
C:\xampp\htdocs\WebName\resources\engine\ajax\signup.php on line 12
I still can't figure out what's the problem. I'm 99% sure it's correct.
The "$ENGINE" is correct, and the class is correct too (Netbeans suggests me class methods and variables).
signup.php:
<?php
/* Created on: 13/12/2011
* Author:
*
* Description: User signup procedure.
*/
require_once("../settings.php");
require_once($ENGINE."/classUser.php");
$user = new User();
$user->createUser($_POST["username"], $_POST["email"], $_POST["password"]);
?>
classUser.php:
<?php
/* Created on: 13/12/2011
* Author:
*
* Description: This class manages users.
*/
require_once("settings.php");
require_once($LIBRARY."/cassandraphp/cassandra.php");
class User {
public function createUser($username, $email, $password){
$cassandra = Cassandra::createInstance($CASSANDRASERVER);
$cassandra->set(
"user.".$username,
array(
'ID' => uniqid(),
'Username' => $username,
'Email' => $email,
'Password' => $password
)
);
}
}
?>
Check to make sure your environment isn't being picky about your opening tags. My configuration requires:
<?php
If I try to use:
<?
Then I get the same error as you.
Short tags can be enabled through the INI setting short_open_tag.
if ( ! class_exists('User'))
die('There is no hope!');
I had this problem and the solution was namespaces. The included file was included in its own namespace. Obvious thing, easy to overlook.
It may also be, that you by mistake commented out such a line like require_once __DIR__.'/../vendor/autoload.php'; --- your namespaces are not loaded.
Or you forget to add a classmap to the composer, thus classes are not autoloaded and are not available. For example,
"autoload": {
"psr-4": {
"": "src/"
},
"classmap": [
"dir/YourClass.php",
]
},
"require": {
"php": ">=5.3.9",
"symfony/symfony": "2.8.*",
First of all check if $ENGINE."/classUser.php" is a valid name of existing file.
Try this:
var_dump(file_exists($ENGINE."/classUser.php"));
The problem went away when I did
sudo service apache2 restart
My fail might be useful to someone, so I thought I would post as I finally figured out what the issue was. I was autoloading classes like this:
define("PROJECT_PATH", __DIR__);
// Autoload class definitions
function my_autoload($class) {
if(preg_match('/\A\w+\Z/', $class)) {
include(PROJECT_PATH . '/classes/' . $class . '.class.php');
}
}
spl_autoload_register('my_autoload');
In my /classes folder I had 4 classes:
dbobject.class.php
meeting.class.php
session.class.php
user.class.php
When I later created a new class called:
cscmeeting.class.php
I started getting the can't load DbObject class. I simply could not figure out what was wrong. As soon as I deleted cscmeeting.class.php from the directory, it worked again.
I finally realized that it was looping through the directory alphabetically and prior to cscmeeting.class.php the first class that got loaded was cscmeeting.class.php since it started with D. But when I add the new class, which starts with C it would load that first and it extended the DbObject class. So it chocked every time.
I ended up naming my DbObject class to _dbobject.class.php and it always loads that first.
I realize my naming conventions are probably not great and that's why I was having issues. But I'm new to OOP so doing my best.
As a more systematic and structured solution you could define folders where your classes are stored and create an autoloader (__autoload()) which will search the class files in defined places:
require_once("../settings.php");
define('DIR_CLASSES', '/path/to/the/classes/folder/'); // this can be inside your settings.php
$user = new User();
$user->createUser($_POST["username"], $_POST["email"], $_POST["password"]);
function __autoload($classname) {
if(file_exists(DIR_CLASSES . 'class' . $classname . '.php')) {
include_once(DIR_CLASSES . 'class' . $classname . '.php'); // looking for the class in the project's classes folder
} else {
include_once($classname . '.php'); // looking for the class in include_path
}
}
It 'happened to me!
The problem is that somehow you include a file with the same file name of the class thus invalidating the same class!
Check the path of inclusion and these checks files with the same name!
Check your file permissions for the correct linux user for classUser.php
Check File Permissions
Check File size.
Sometimes an inaccessible or corrupted file would be the problem, as was in my case
you should declare namespace in the ClassUser.php, something like this:
<?php
namespace app; // where 'app' is a folder declared as a root for the project
class ClassUser{
public function test(){
//log something here
}
}
?>
Then you can add the class in your other php files like this:
<?php
use app\ClassUser;
$classUserLcl = new ClassUser();
$classUserLcl->test();
?>
and you are done.
Otherwize it will abuse:
You Oh! its a Fatal error : Uncaught Error: Class 'app\ClassUser' not found in ...
When namespace declaration is part of your php class file "this kind of weird errors tends to appear".
Solution: Use namespace with {, your code shows like this:
<?php
namespace path_to\lib {
require_once "folder/php_class_file_where_namespace_declaration_is_part_of_it.php";
**YOUR CODE HERE**
<?php } ?>
Double check your autoloader's requirements & namespaces.
For example, does your autoloader require your namespace to match the
folder structure of where the file is located? If so, make sure they
match.
Another example, does your autoloader require your filenames to
follow a certain pattern/is it case sensitive? If so, make sure the
filename follows the correct pattern.
And of course if the class is in a namespace make sure to include it
properly with a fully qualified class name (/Path/ClassName) or with a use statement at the top of your file.
Maybe it is how you use new User().
Set path something like
$user = new \resources\engine\ajax\User();
If you've included the file correctly and file exists and still getting error:
Then make sure:
Your included file contains the class and is not defined within any namespace.
If the class is in a namespace then:
instead of new YourClass() you've to do new YourNamespace\YourClass()
Yes this happen in cases when use a trait or extend a class, you should be aware to instantiate the class after the class declaration for example:
This example will trigger class not found error:
$class = new A();
class A {
use SomeTrait;
}
To make it to work move the initialization step in the bottom like so:
class A {
use SomeTrait;
}
$class = new A();
I found I had to use the use keyword, as well as the include statement. Tested it with either missing, and it doesn't work.
namespace foo;
use src\config\object;
include('config/object.php');