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.
Related
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.
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 have a small framerwork and in my scripts I use autoload (I just now aware that I need to start getting rid of this function in my scripts)
I am now trying to use the Twilio API, in their code, they use the spl_autoload_register function. After the logic block that the twilio code is called in the rest of the script breaks down when I make a new call to one of my classes
my file structure is this
/classes/
autoload.php
DB_Connect.php
/classes/Twilio/
/sms/Twilio/Services/
twilo.php
The script that is breaking down looks something like this
<?php
include(classes/autoload.php);
if($something_is_true){
requrie_once(sms/Twilio/Services/Twilio.php);
//here is where the spl_autoload_register() is called
}
$connection = new DB_Connect();
//script is broken here
What do I need to do now in the Classes folder to make all of the classes work?
The reason probably is that your autoloader (__autoload()) gets completely replaced once spl_autoload_register() is called:
If your code has an existing __autoload() function then this function must be explicitly registered on the __autoload stack. This is because spl_autoload_register() will effectively replace the engine cache for the __autoload() function by either spl_autoload() or spl_autoload_call().
You can update your script to work within seconds, as only a slight change is needed to properly register your autoloader.
Currently it looks like this:
function __autoload($class) {
// ...
}
Change it like this (assuming you are running PHP 5.3):
spl_autoload_register(function ($class) {
// ...
});
Before PHP 5.3 adding this should work as well:
spl_autoload_register('__autoload');
Let's say I've got two files class.php and page.php
class.php
<?php
class IUarts {
function __construct() {
$this->data = get_data('mydata');
}
}
?>
That's a very rudamentary example, but let's say I want to use:
$vars = new IUarts();
print($vars->data);
in my page.php file; how do I go about doing that? If I do include(LIB.'/class.php'); it yells at me and gives me Fatal error: Cannot redeclare class IUarts in /dir/class.php on line 4
You can use include/include_once or require/require_once
require_once('class.php');
Alternatively, use autoloading
by adding to page.php
<?php
function my_autoloader($class) {
include 'classes/' . $class . '.class.php';
}
spl_autoload_register('my_autoloader');
$vars = new IUarts();
print($vars->data);
?>
It also works adding that __autoload function in a lib that you include on every file like utils.php.
There is also this post that has a nice and different approach.
Efficient PHP auto-loading and naming strategies
In this case, it appears that you've already included the file somewhere. But for class files, you should really "include" them using require_once to avoid that sort of thing; it won't include the file if it already has been. (And you should usually use require[_once], not include[_once], the difference being that require will cause a fatal error if the file doesn't exist, instead of just issuing a warning.)
Use include_once instead.
This error means that you have already included this file.
include_once(LIB.'/class.php');
use
require_once(__DIR__.'/_path/_of/_filename.php');
This will also help in importing files in from different folders.
Try extends method to inherit the classes in that file and reuse the functions
Use include("class.classname.php");
And class should use <?php //code ?> not <? //code ?>
I have a Problem developing in PHP. First I have to say that I'm not the experienced PHP developer on this Planet.
My Code/Problem is as followed:
In file Controllers\TestController.php:
<?php
namespace My\Test\Controllers;
class TestController
{
public function HelloTest()
{
echo 'Hello!';
}
}
?>
When I want to include this class in another php file like this
File Models\TestModel.php:
<?php
namespace My\Test\Models;
use My\Test\Controllers;
class TestModel
{
public function TestModelFunction()
{
$control = new TestClass();
$control->HelloTest();
}
}
?>
File index.php_
<?php
use My\Test\Models;
$model = new TestModel();
$model->TestModelFunction();
?>
That just won't work... I'll always get the following error:
Class 'TestModel' not found!
When I now add:
include_once 'Models/TestModel.php' in index.php
AND
include_once '..Controllers/TestController.php' in TestModel.php
then it works...
Folder Structure:
Project
|-Models
| TestModel.php
|-Controllers
| TestController.php
|index.php
But do I really have to specify every Time where the files are?
Yes you will always have to include the files that define your classes.
The namespace is just a way to package your classes together, not a way to automatically include PHP files.
If your are looking for a way to automatically include PHP files when needed, have a look on autoload.
Namespaces logically separate code into different... well, namespaces. It has nothing to do with including the files that contain code for that namespace. So yes, you do need to include the file in some way or another (e.g. autoloaders) in addition to namespacing them.
Another approach is to use autoloader (http://php.net/manual/en/language.oop5.autoload.php). You can find some good open source autoloaders out there.