Composer psr-0 autoloading of custom namespaces does not work - php

I have trouble adding my own namespaces to composer with PSR-0. I have read this and this but I still can't make it work
composer.json
{
"require": {
"klein/klein": "2.0.x",
"doctrine/orm": "2.4.4"
},
"autoload": {
"psr-0": {
"mynamespace": "src/"
}
}
}
The src folder is placed inside the same directory as composer.json
The src directory has the following structure
src
└── mynamespace
├── Keys.php
Keys.php
<?php
namespace mynamespace\Keys;
define ("API_KEY", "XXXXXXXXXXXX");
?>
index.php
use Klein\Klein;
use mynamespace\Keys;
require_once __DIR__ . '/vendor/autoload.php';
$klein = new Klein(); // works
echo API_KEY; // Undefined constant

You can only load classes, interfaces and traits with autoloading.
Because all you do is add a use clause which does not do anything by itself with autoloading (i.e. it does not load something), and you do not use a class, nothing happens.
I recommend using class constants. They may be put into classes or interfaces:
namespace mynamespace;
interface Keys {
const API_KEY = 'XXXXXXXX';
}
use mynamespace/Keys;
echo Keys::API_KEY;

Related

How to use composer psr-4 fallback correctly

I have one directory that is going to keep all "helper" classes and functions. Let's call the directory helpers.
I want to configure PSR-4 fallback directory to point to this helpers directory:
"autoload": {
"psr-4": {
"": "helpers/"
}
}
From Composer documentation:
... fallback directory where any namespace will be looked for.
So my understanding is that if my files/classes in that directory have PSR-4 compliant names my application should be able to find them there.
Now I created a file helpers/Logger.php with class Logger
What namespace should be for this class in order to 1) comply with PSR-4 and 2) just work?
I have tried
namespace Logger;
And load class as
$logger = new Logger();
But I receive error Class Logger not found
Deeper dive into composer code (loadClass() method) showed me that it actually finds and includes the file helpers/Logger.php, but the class still cannot be found for some reason.
According to PSR-4 namespace should be something like this:
namespace Helpers;
And class should be called like this:
$logger = new Helpers\Logger();
I have Class Helpers\Logger not found, but in addition the file helpers/Logger.php is not even included.
The logic inside Composer's loadClass() method for fallback is following:
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
........
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
So it actually tries to match the file name against the fully qualified class name.
So it seems that I am missing something in my understanding of PSR-4.
But what exactly?
Edit
To check it all I run a simple file from project root, all other libraries that are configured via composer are loaded correctly (for example, Pimple is working fine):
<?php
require_once __DIR__ . '/vendor/autoload.php';
$app = new \Pimple\Container();
/** Register logger */
$app['logger'] = function ($c) {
return new Helpers\Logger();
};
$app['logger']->info('test');
This fallback works as a definition of directory for global namespace. So yes, it may be used for autoloading any class in any namespace, but you still need to follow PSR-4 rules for them. Directory structure should represent namespaces structure. If you have rules like:
"autoload": {
"psr-4": {
"": "helpers/"
}
}
your Helpers\Logger class should be in helpers/Helpers/Logger.php, because in this way Composer will resolve class file path from autoloading rules.
helpers/Helpers/Logger.php
^ ^ ^
| | |
| | Class name part
| |
| Namespace part
|
Static prefix for global namespace
PSR4 is working case-sensitive, so if you place a class in the folder helpers and the class itself uses the namespace Helpers, that won't work.

Composer autoload not including my custom namespaces (Silex)

I'm developing a REST API with Silex and I'm facing a problem regarding autoloading of my custom librairy. It looks like Composer's autoload is not including it, because when I include it myself it works.
# The autoload section in composer.json
# Tried with :
# "Oc\\": "src/Oc"
# "Oc\\": "src/"
# "": "src/"
"autoload": {
"psr-4": {
"Oc\\": "src/"
}
}
<?php
// api/index.php <-- public-facing API
require_once __DIR__.'/../vendor/autoload.php';
$app = require __DIR__.'/../src/app.php';
require __DIR__.'/../src/routes.php'; // <--
$app->run();
<?php
// src/routes.php
// When uncommented, it works!
//include('Oc/ParseImport.php');
use Symfony\Component\HttpFoundation\Response;
use Oc\ParseImport;
$app->get('/hello', function () use ($app) {
return new Response(Oc\ParseImport(), 200);
});
<?php
// src/Oc/ParseImport.php
namespace Oc {
function ParseImport() {
return 'foobar!';
}
}
I run composer dumpautoload after each composer.json manipulation, and I do see the line 'Oc\\' => array($baseDir . '/src/Oc') (or anything I tried) in vendor/composer/autoload_psr4.php.
I can't figure out what is wrong.
Almost everything you did was correct.
When trying to autoload classes in a namespace, given that a class is named Oc\Foo and is located in the file src/Oc/Foo.php, the correct autoloading would be "PSR-4": { "Oc\\": "src/Oc" }.
However, you do not have a class. You have a function. And functions cannot be autoloaded by PHP until now. It has been proposed more than once (the one proposal I found easily is https://wiki.php.net/rfc/function_autoloading), but until now this feature hasn't been implemented.
Your alternative solutions:
Move the function into a static method of a class. Classes can be autoloaded.
Include the function definition as "files" autoloading: "files": ["src/Oc/ParseImport.php"] Note that this approach will always include that file even if it isn't being used - but there is no other way to include functions in PHP.
As illustration see how Guzzle did it:
Autoloading in composer.json
Conditional include of functions based on function_exists
Function definition

Class not found - PSR-4 namespaced autoloading

I wanted to set up PSR-4 autoloading for a class I wrote. However I keep getting the error Fatal error: Class 'Glowdemon1\Translxtor\LangParserXML' not found in C:\xampp\htdocs\translator\index.php on line 5
Folder structure(can't post img yet):
LangParserXML.class.php
namespace Glowdemon1\Translxtor;
class LangParserXML extends ErrorHandler implements ParserInterface{
...
index.php
require_once('vendor/autoload.php');
$translator = new Glowdemon1\Translxtor\LangParserXML('nl.xml');
composer.json
"autoload": {
"psr-4": {
"Glowdemon1\\": "src/"
}
}
autoload_psr4.php
return array(
'Glowdemon1\\' => array($baseDir . '/src'),
);
I have looked trough countless posts, yet no solutions. This is also posted on https://github.com/glowdemon1/translxtor in case you want a deeper look. Thanks.
Updates your composer.json to :
"autoload": {
"psr-4": {
"Glowdemon1\\Translxtor\\": "src/"
}
}
Or add a src/Transxtor/ directory before your LangParserXMl
Also, your filename cannot contain ".class". It should just be called LangParserXML.php.
I think you should have a Translxtor folder within src containing LangParserXML.class.php and Translator.class.php:
The contiguous sub-namespace names after the "namespace prefix" correspond to a subdirectory within a "base directory", in which the namespace separators represent directory separators. The subdirectory name MUST match the case of the sub-namespace names.
Source: http://www.php-fig.org/psr/psr-4/
`

How to use __autoload function when use composer load

app/Core
contollers
This is my website structure to put the main class, I user composer psr-4 rule to import class under app/Core folder.
composer.json
{
"autoload": {
"psr-4": {
"Core\\": ["app/Core"]
}
}
}
index.php
<?php
include 'vendor/autoload.php';
new Core/Api; // it's work
It works fine, but I want to autoload class under controllers folder without use namespace, so I use __autoload function like:
index.php
<?php
include 'vendor/autoload.php';
function __autoload($class_name) {
include 'controllers/' . $class_name . '.php';
}
new Test // Fatal error: Class 'test'
If I remove include 'vendor/autoload.php'; it will work, so I think the code is correct, I know I can use classmap in composer.json, but it need to dump-autoload everytime I add a new class, how to deal with the conflict?
You do not have to use your own implementation of autoloading. You could use composer autoloading for all classes.
{
"autoload": {
"psr-0": { "": "src/" }
}
}
https://getcomposer.org/doc/04-schema.md#psr-0
Or, you could create class map
https://getcomposer.org/doc/04-schema.md#classmap
p.s. indeed, you could use empty namespace with psr-4.

How do you register a namespace with Silex autoloader

I'm experimenting with creating an extension with the Silex php micro framework for user authentication but I can't seem to get the autoloader to work. Can anyone shed any light?
I have a directory structure like this (truncated)
usertest
|_lib
| |_silex.phar
| |_MyNamespace
| |_UserExtension.php
| |_User.php
|_www
|_index.php
The pertinent bits of index.php, which serves as the bootstrap and the front controller look like this:
require '../lib/silex.phar';
use Silex\Application;
use MyNamespace\UserExtension;
$app = new Application();
$app['autoloader']->registerNamespace( 'MyNamespace', '../lib' );
$app->register( new UserExtension() );
The class I'm trying to load looks similar this:
namespace MyNamespace;
use Silex\Application;
use Silex\ExtensionInterface;
class UserExtension implements ExtensionInterface {
public function register( Application $app ) {
$app['user'] = $app->share( function() use( $app ) {
return new User();
});
}
}
All pretty straight forward except it throws this error:
Fatal error: Class 'MyNamespace\UserExtension' not found in /home/meouw/Projects/php/usertest/www/index.php on line 8
I have dabbled with symfony2 and have successfully followed the instructions for setting up the universal class loader, but in this instance I am stumped. Am I missing something? Any help would be appreciated.
In recent versions of Silex the autoloader is deprecated and you should register all your namespaces through the composer.json file which imo is a nicer solution because you are centralizing your autoloading definitions.
Example:
{
"require": {
"silex/silex": "1.0.*#dev"
},
"autoload": {
"psr-0": {
"MyNameSpace": "src/"
}
}
}
In fact when you try to access the autoloader in any recent version of Silex the following RuntimeException is thrown:
You tried to access the autoloader service. The autoloader has been removed from Silex. It is recommended that you use Composer to manage your dependencies and handle your autoloading. See http://getcomposer.org for more information.
I'd use
$app['autoloader']->registerNamespace('MyNamespace', __DIR__.'/../lib');
Deprecated - As of 2014-10-21 PSR-0 has been marked as deprecated.
PSR-4 is now recommended as an alternative
That is why you should use PSR-4 syntax in composer.json
{
"require": {
"silex/silex": "1.0.*#dev",
},
"autoload": {
"psr-4": {
"Vendor\\Namespace\\": "/path"
}
}
}
To register namespaces, just call registerNamespaces() like this:
$app = new Silex\Application();
$app['autoloader']->registerNamespaces(array(
'Symfony' => __DIR__.'/../vendor/',
'Panda' => __DIR__.'/../vendor/SilexDiscountServiceProvider/src',
'Knp' => __DIR__.'/../vendor/KnpSilexExtensions/',
// ...
));
Both adding appropriate statement to the autoload section of composer.json and registering namespaces directly calling registerNamespace was not working for me, until I executed composer update in the projects folder.

Categories