Is there a way to have an autoload file you created run before the vendor autoload is called? We seem to be running into an issue with SimpleSAML's autoload overriding one of the autoload files we created. I am new to Composer, and couldn't seem to find any solutions online.
I tried including our autoload file in the file that needs it as well and that still did not work.
A workaround is to just include the files explicitly, but being able to use the autoloader would be preferred.
Yes, you can register an autoloader and prepend it to the queue, for example:
spl_autoload_register(function($class) {
// ...
}, true, true);
The last parameter (true) will prepend this autoloader into the queue, so, it'll be called at first and to do that, you've to register your autoloader at the very early of your script, maybe just right after you include the vendor autoloader. Read more here.
Related
In YII2 Framework
Path of File is root\vendor\yiisoft\yii2-httpclient\Client.php
Namespace defined in above mentioned file is - namespace yii\httpclient;
Now when I use this namespace in other file while setting up Google ReCaptcha
by writing "use yii\httpclient\Client"
then I am getting error "Class yii\httpclient\Client" not found
So I want to know whether namespaces are path dependent ? or is there a routing file or htaccess..etc where I can define the actual path of namespaces used in project, which YII2 compiler will refer to locate the file / class ?
Namespaces themselves are not dependent on file path.
But you are probably mistaking what use clause does.
If you have this line in file:
use yii\httpclient\Client;
It doesn't mean that the class is loaded. It only tells parser that you mean yii\httpclient\Client every time you use Client class in that file.
PHP has something called autoload to make sure you don't have manually require files for each class you are using. Autoloaders are called every time you are using some class if that class hasn't been loaded yet. When they are called they are given the class name and they check if they know how to load that class.
Now, even if the namespaces itself are not dependent on file path autoloaders usually uses those namespaces to decide where to look for the file containing that class.
And as Nigel Ren mentioned in comment, there exist PSR-4 recommendation how to choose namespace and file structure to make sure that autoloader will know where to look for class.
Yii2 projects usually uses 2 autoloaders.
The Yii's own autoloader and autoloader generated by composer.
Since your question is about class that comes from vendor\yiisoft\yii2-httpclient the autoloader generated by composer.
If you check the composer.json file in that package you can see that it has autoloader section with psr-4 key. That tells composer that when it generates its autoloader it should be set to look for any class from yii\httpclient namespace in src folder of that package.
To make sure the composer's autoloader is working properly you have to go through following steps:
The yiisoft\yii2-httpclient package should be installed by composer.
If you need to regenerate composer's autoloader you can run:
composer dump-autoload
The composer autoloader must be included in your application's entry point (usually /web/index.php or /yii files).
Check if those files have this line:
// in case of /web/index.php
require(__DIR__ . '/../vendor/autoload.php');
//in case of /yii
require(__DIR__ . '/vendor/autoload.php');
I'm developing a certain PHP framework for WordPress, and I want to give my users the option to use composer to install it as a package, or to install it manually. If composer is used, then a psr-4 class autoloader handles everything. If not, then all files must be loaded manually during the framework's bootstrapping process.
Is there a safe way to check whether composer's autoloader is being used in a given WordPress environment?
Currently i'm using:
if( !class_exists('Composer\\Autoload\\ClassLoader') )
{
// Manually include files if composer is not used.
require_once 'some/files.php';
}
However, if in a given WordPress environment there is a plugin that uses composer internally, then the above if statement will return true even though other plugins have no access to it.
The solution, as it turns out, is quite simple. You need to create 2 different bootstrapping files, say manual-bootstrap.php and composer-bootstrap.php. Then add the following lines to composer.json:
"autoload": {
"files": ["composer-bootstrap.php"]
}
composer-bootstrap.php will only be called if composer is used to load the framework as a dependency. Users that want to load the framework manually will use manual-bootstrap.php instead.
if(class_exists("\Composer\Autoload\ClassLoader"))
{
// a composer autoload.php has already been included/required
}
I'm using composer in a legacy project that have lots of classes with no namespace. Refactoring is not an option (it's a very huge application), but all new modules are fully psr-4 compliant. The legacy code has it's own autoload method (using a class map, pretty efficient).
My problem is: no matter in which order I add the autoloader methods, composer autoloader ALWAYS COMES FIRST! This is slowing down the load of each single class: every time I call a class from the legacy code, it first tries to match it against all composer autoload options (including the findFileWithExtension() ), and only then it calls the alternative autoloader.
I've inspected it using PHPStorm+XDebug, and no matter which autoloader I include first, Composer autoload is always called before the legacy one.
Is there a way to change this behaviour??
Thanks in advance!!
Ok, guys, I found the solution and want to share it with you: the spl_autoload_register() function has a third parameter: $prepend. When set to true, it will prepend the autoload function to the autoload queue, instead of appending it (it's actually documented at the official PHP Documentation). Composer always sets it to true, so that its autoloader is always called first. To fix it, I changed the legacy autoloader, setting $prepend to true, and called it AFTER including composer's autoload.
Hope it helps someone! :)
Pass true as a third argument to the spl_autoload_register:
spl_autoload_register(your_autoload_func(), true, true);
You need to be aware that composer use different ways to include php files, check vendor/composer/autoload_real.php for details, and remember that composer can include files directly in the place where you include
require_once('vendor' . DIRECTORY_SEPARATOR . 'autoload.php');
so if you are lucky to have vendor/composer/autoload_static.php remember that adding $prepend parameter to your own spl_autoload_register() may not be enough.
I am trying to use this composer package with a new project I am working on https://packagist.org/packages/activecollab/activecollab-sdk. However when i try and create a new class I keep getting the following errors.
Fatal error: Class 'ActiveCollab\Client' not found
The file that is throwing this error looks like this.
require "vendor/autoload.php";
new ActiveCollab\Client;
Which is just being used to test if the files are being loaded in properly. The composer.json of the file which I am trying to use looks like such. And I have a feeling the problem is in this file but I can't figure out what.
stuff...
"autoload": {
"psr-0": {
"ActiveCollab\\": "ActiveCollab"
}
}
...stuff
Also looking at the autload_namespaces.php file it is being generated as such.
<?php
// autoload_namespaces.php #generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'ActiveCollab' => array($vendorDir . '/activecollab/activecollab-sdk/ActiveCollab'),
);
I have used psr-0 in some composer packages of my own and everything looks to be right except maybe the camel case in the namespace but i don't see this as being disallowed in the php proposal for psr-0.
Thanks for any help this has been driving me crazy.
The thing is: You cannot simply add a composer.json file with a random autoloading configuration and hope that it works - it actually has to match the naming scheme you are using. That is what this project got wrong, and nobody tested it. Which probably means nobody uses this library, and you can expect no support from the creators due to lack of interest.
But let's see how they react on my pull request to get things back to working again.
The composer config looks fine: Is it just the case that you omitted the leading \ from your class name?
new \ActiveCollab\Client;
You'll need that if your code is inside another namespace, as it will load it relative to the current namespace.
EDIT: I've just checked out that library, and even with the above fix, the autoloader wasn't quite working. The autoloader may also be broken due to the composer.json file for the library specifying a PSR0 autoloader, but using ".class.php" extensions (not PSR0 compatible). An autoload.php file is included with the library, so if you just require that file, you should be able to use the classes:
require 'vendor/activecollab/activecollab-sdk/ActiveCollab/autoload.php';
After doing this, I was able to use the class.
I've got some libraries loaded through composer, and I'm wondering if it's possible to add my own library in the /vendor map, and then to have the composer autoloader load it? The structure would be something like /vendor/mylibrary/ and then a namespace mylibrary.
Would this be possible? Also would it be possible to add a different map to the composer autoloader? Like for example /app/src/ and then to have it load all the classes in that folder? Or do I have to make my own loader for that?
Thanks
Reading the composer documentation:
You can even add your own code to the autoloader by adding an autoload field to composer.json.
{
"autoload": {
"psr-0": {"Acme": "src/"}
}
}
Composer will register a PSR-0 autoloader for the Acme namespace.
You define a mapping from namespaces to directories. The src directory would be in your project root, on the same level as vendor directory is. An example filename would be src/Acme/Foo.php containing an Acme\Foo class.
After adding the autoload field, you have to re-run install to
re-generate the vendor/autoload.php file.
So basically, you just need to follow PSR-0, and tell composer where to find your library, by adding that line to your composer.json
Yes.You can achieve it. Configure your composer.json file as following:
{
"autoload": {
"classmap": [ "classes" ]
}
Here classes is the name of the directory where you have all your application related classes.Vendor related class should be auto detected as well. Just add the following line to achieve both at the same time:
require 'vendor/autoload.php';
And you can use the namesapce to reference your class like the following:
use classes\Model\Article;
Yes, of course it is possible to add own libraries and you should feel highly encouraged to do so. If your library is available publicly, you can simply register it at packagist.org. If not, it's a bit more complicated, but not impossible.
If your project does not follow the PSR-0 standard, composer will create a classmap for you. A custom autoloader is not supported.
I'd recommend you to read the (really excellent) documentation about all this and come back, if you're running into problems.
http://getcomposer.org/doc/