Open vendor/composer/autoload_real.php and look at this code:
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
When:
spl_autoload_register(array('ComposerAutoloaderInitf06647a07a90b762eb34553a7bce155e', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInitf06647a07a90b762eb34553a7bce155e', 'loadClassLoader'));
Why Composer do this? And not this:
require_once __DIR__ . '/ClassLoader.php';
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
The reason is that multiple autoloaders might be present concurrently in one process if for example you run phpunit installed via composer, then your test bootstrap file will also include your project class loader, and so if we did a simple require it would redefine the ClassLoader class and do a fatal error. Using require_once would not work either since the ClassLoader.php file is present twice (one in PHPUnit, one in the project) with different paths. PHP would still include each of these once, leading in class redefinition.
This could be fixed with a simple if (!class_exists()) {} around the require, but unfortunately that kind of conditional class definition messes up APC on high traffic sites so we had to resort to this strange temporary autoloader hack to make it work everywhere.
Related
I am work on legacy app that includes dozens and dozens of different php scripts, all written before Composer was widespread in use.
I needed to use a package (for sending email) only available through Composer, so I created a composer directory and included it into one script like so:
include_once("/home/soccer/src/autoload.php"); // the old autoloader
require '/home/soccer/src/Mailgun/vendor/autoload.php';
use Mailgun\Mailgun;
Now the problem is that Composer's autoload (shown in line 2) works fine, and I can send mail, however now the important libraries from line 1 do not work:
PHP Fatal error: Class 'DB' not found in .....
There is a file at:
/home/soccer/src/DB.php
that is the most basic MySQL db loader imaginable. I tried adding a namespace to it with:
namespace Footyscores;
and then in the PHP script adding **Footyscores** to the function call, but no luck there, same error.
Here is the legacy autoloader:
include_once "/home/soccer/src/settings.php";
function __autoload($class)
{
global $srcDir;
$parts = explode('\\', $class);
$file = end($parts);
include_once $srcDir . $file . '.php';
}
How is I fix this? Thanks!
I want to include class Proxy from
./proxy/Proxy.php in ./index.php
require_once 'proxy/Proxy.php';
$proxy = new Proxy();
But next I want to use namespaces so I made:
./proxy/Proxy.php
namespace proxy;
class Proxy
{
[...]
and
./index.php
$proxy = new \proxy\Proxy();
or
$proxy = new proxy\Proxy();
or
use proxy\Proxy;
$proxy = new Proxy();
and I always get:
Fatal error: Uncaught Error: Class 'proxy\Proxy' not found in /var/www/proxy/index.php
What is wrong?
Firstly, if you are going to use namepaces, make them PSR-4 autoloader compliant! Check this link:
http://www.php-fig.org/psr/psr-4/
In other words, I'm asking you to change your namespace to Proxy with a capital.
Secondly, to get autoloading working, you need to register an autoloader. You can do it yourself by checking this out http://php.net/manual/en/function.spl-autoload-register.php, or, the better way is to install Composer (https://getcomposer.org/).
Using Composer then, if you aren't currently using it, run composer init from your site root, which will generate a composer.json.
Inside the Json, add this entry:
"autoload": {
"psr-4": {
"Proxy": "src/"
},
},
That assumes all classes beginning with namespace Proxy go in the src directory.
Since you made changes to the autoloading config, run composer dumpautoload and it will generate fresh classmaps.
Finally, in your scripts, require_once 'vendor/autoload.php and you'll never need require a class again!
require_once 'vendor/autoload.php';
use Proxy\Proxy;
$proxy = new Proxy();
The convention is based on file path and name, so src/Proxy.php is namepace Proxy, class Proxy. src/Something/Else.php would be namespace Proxy\Something with class Else.
Have fun! :-D
Try the following inside your index.php:
include 'proxy/Proxy.php';
use proxy\Proxy;
$proxy = new Proxy();
This file with the class needs to be included in order to be accessible. Just calling its namespace isn't enough.
^^The comment from mega6382I should do the trick.
But I wanted to maybe help you any further in your development, I'd suggest you want to autoload the files when you need them? You can use PHP it's own autoloader for it: "spl_autoload_register!".
I'd also recommend you use some better namespaces, \proxy\Proxy makes no sense at all...
We're building a new Slim application and we want to use PSR4-Autoloading with namespaces in our code.
We found two ways to do that, via Composer i.e.:
"autoload": {
"psr-4": {
"App\\Controller\\": "app/controllers",
"App\\Middleware\\": "app/middleware",
"App\\Model\\": "app/models"
}
},
Or via spl_autoload_register i.e.:
spl_autoload_register(function ($class_name) {
$filename = __DIR__ . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $class_name) . '.php';
require $filename;
});
What determines which method we should go with?
The version with spl_autoload_register could be faster, because it is directly suited to you. But because you are using Composer for autoloading your depenendecies, your version will be likely be as fast or even slower than the Composer implementation.
There is a principle called Don't repeat yourself so why making something new, when the people from Composer already thought about it and implemented it.
That being said, Composer also uses spl_autoload_register internally
Conclusion: Use the Composer psr-4 autoload, its probably more robust than your implementation, and equally as fast performance-wise.
I have run into a few problems trying to make Codeception work with my Slim Framework project.
First, I cannot call a service/repository/model from a unit class without it being in the same namespace. When the tests are run, the following code block results in:
[Error] Class 'OMIS\Services\UserService' not found`
// tests
public function testUser()
{
$userService = new UserService();
$this->tester->assertNotNull($userService->find(1));
}
Secondly, I am trying to get Codeception to interact with a testing database I have set up. Because I am using Laravel's Eloquent ORM I thought that enabling the Laravel ORM module for Codeception in unit.suite.yml might work as there is no Slim module available for unit testing, but I get the following error when running the tests:
ExampleTest: UserPHP Fatal error: Class 'Symfony\Component\HttpKernel\Client' not found in /Users/me/dev/project/vendor/codeception/codeception/src/Codeception/Lib/Connector/Laravel5.php on line 13
Fatal error: Class 'Symfony\Component\HttpKernel\Client' not found in /Users/Me/dev/project/vendor/codeception/codeception/src/Codeception/Lib/Connector/Laravel5.php on line 13
Here is the relevant part of my bootstrap/app.php file
session_start();
require __DIR__ . '/../vendor/autoload.php';
// Load environment variables
$dotenv = new Dotenv(__DIR__.'/../');
$dotenv->load();
$container = require __DIR__.'/../config/container.php';
$app = $container->get(App::class);
$config = new Config(__DIR__.'/../config/database.php');
$db = $config->get('db');
$capsule = new Capsule();
$capsule->addConnection($db);
$capsule->setAsGlobal();
$capsule->bootEloquent();
require __DIR__.'/../config/dependencies.php';
require __DIR__.'/../config/services.php';
require __DIR__.'/../config/controllers.php';
require __DIR__ . '/../app/routes.php';
// Middleware
Zend Framework 2 claims to have a "use-at-will" design that allows you to easily use any of its modules without committing to the full stack. I need a good database access layer, and from the docs and recommendations online I like the look of Zend\Db. I've placed the Zend/Db folder in my /lib directory, but I'm having trouble getting PHP to recognize the Zend\Db\Adapter\Adapter class. I keep getting a fatal error when I try to use it:
Fatal error: Class 'Zend\Db\Adapter\Adapter' not found in /home/username/public_html/test.php on line 6
I've tried setting ZF2_PATH in my .htaccess:
SetEnv ZF2_PATH /home/username/public_html/lib/Zend
I've tried setting the include path in my code:
set_include_path( $_SERVER['DOCUMENT_ROOT'] . '/lib' . PATH_SEPARATOR . get_include_path() );
I've tried explicitly loading and instantiating the Zend\Loader:
require_once 'lib/Zend/Loader/StandardAutoloader.php';
$zendLoader = new Zend\Loader\StandardAutoloader();
$zendLoader->register();
None of these have had any effect. I tried explicitly requiring Zend/Db/Adapter/Adapter.php, and that did fix the error I'm seeing, but then I just get the same error for one of its dependencies, so that's not a practical solution.
What am I doing wrong here? Is ZF2 just not really designed for this kind of modular usage, or am I missing something?
EDIT: I got this to work by writing my own autoload function:
function autoloader($class) {
$path = explode('\\', $class);
foreach ($path as $p) {
$cp .= DIRECTORY_SEPARATOR . $p;
}
include __DIR__ . '/lib/' . $cp . '.php';
}
spl_autoload_register(autoloader);
This sort of makes sense -- obviously if I'm using the db module without the rest of the framework, I can't expect the framework to do autoloading for me -- except I still don't understand why manually loading Zend\Loader didn't solve the problem. Isn't handling autoloading the point of Zend\Loader? Anyway, I have a workable solution for now, but if there's a better solution I'd love to hear it.
I strongly recommend you check out composer. It really simplifies managing dependencies between a ton of modern PHP libraries, as well as autoloading.
For instance, if you were starting you project, and you knew you wanted to pull in zend-db, you'd do something like this:
$ mkdir myproject
$ cd myproject
$ curl -s https://getcomposer.org/installer | php
$ ./composer.phar require zendframework/zend-db:2.1.1
That last line will cause composer to spring into action. It will create a directory called "vendor" where it keeps all the libraries it manages. It then will check out version 2.1.1 of zend-db in there, and set up an vendor/autoload.php which you'll require in your project.
Then you can test it out. Create myproject/index.php like so:
<?php
require_once "vendor/autoload.php";
$adapter = new Zend\Db\Adapter\Adapter(array(
'driver' => 'Pdo_Sqlite',
'database' => 'path/to/sqlite.db'
));
And it just works.
Later, if you decide you need Zend\Mail too, you just:
$ ./composer.phar require zendframework/zend-mail:2.1.1
and composer will install it, along with a couple of dependencies, and make sure it's available to the autoloader.
Composer is not ZF-specific, either. There's a whole ecosystem of code to explore. Packagist is a good place to start.