Composer PSR-4 autoloading "class not found" debug - php

Yes another question about the "class not found" error. Either I am missing something, or I misunderstood the PSR-4 logic.
My composer library directory sturcture:
"Scanner" => "src" => "Test.php"
Test.php
namespace MyNS;
class Test
{
}
composer.json
"autoload": {
"psr-4": {
"MyNS\\": "src/"
},
}
So, now I load the library in my project with composer and try using it.
require_once("../vendor/autoload.php");
$test = new MyNS\Test();
Which always results in
"Fatal error: Uncaught Error: Class 'MyNS\Test' not found."
. What am I missing? I am staring at this for days now. I have changed folders, I have changed folder names, I have changed uppper to lower and vise versa. Nothing seems to work.
I am using PHP 7.2.2 and Composer version 1.2.2
Even tried this:
require_once("../vendor/autoload.php");
use MyNS\Test;
$scanner = new Test();
Update
I debugt the Composer ClassLoader.php file (findFileWithExtension($class, $ext)) method and apparently my files are never loaded because I get put an echo "Done" and a die(); at the end of this method which means the file is not found and thus not loaded. What is wrong with my composer.json?
{
"name": "test/test",
"type": "library",
"description": "",
"keywords": ["php"],
"homepage": "",
"license": "MIT",
"authors": [
{
"name": "",
"email": "",
"homepage": "",
"role": ""
}
],
"require": {
"php": ">=7.2.2"
},
"autoload": {
"psr-4": {
"MyNS\\": "src/"
}
}
}

To debug what is happening open ClassLoader.php file then go where findFileWithExtension() method is defined to add an echo statement:
# vendor/composer/ClassLoader.php:386
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
// Add this line
echo $file, PHP_EOL;
}
Do not do composer dumpautoload after you manually modified above file until we are done.
Now by executing your PHP file you will see something similar to this at the very beginning of output:
path/to/project/vendor/composer/../../src/Test.php
Which is:
path/to/project/src/Test.php
So this is the file that composer is looking for and should contain something like this:
namespace MyNS;
class Test { }
If there is an issue in including the file then it means you have to care about three things:
Path and filename
Namespace used in file
Class name used in file (class name should be the same as filename)

i think the problem is in your namespace declaration
you calling the class from MyNS but class namespace is namespace MyNS\PSR4;
require_once("../vendor/autoload.php");
$test = new MyNS\Test();
// it should be new MyNS\PSR4\Test();
and make sure, your class file in same directory which you mentioned in composer autoload file
also you have to run dump-autoload command for any change in classnames
you can visit for this autoload feature

Related

Class not found using custom composer package

I have created a custom comoposer package and I want to use it on my project with this composer.json:
{
"name": "papillon/test",
"type": "library",
"version": "dev-master",
"require": {
"php": "^7.1.11"
},
"autoload": {
"psr-4": {
"Papillon\\Fountaine\\Eau\\": "src/Papillon/Fountaine/Eau/"
}
}
}
I compress it in zip. In the main project, I add a folder called repo, where I add de composer package zip. Then, I modify the composer.json of the main project like this:
{
"repositories": [
{
"type": "artifact",
"url": "var/main/repo"
}
],
"require": {
"papillon/test": "dev-master"
}
}
I execute composer update and the pakage is added to vendor folder; all seems to be going well... but if I want to test the package from the main project with this script:
<?php
require (__DIR__ . '/vendor/autoload.php');
use Papillon\Fountaine\Eau\FlowerClass;
echo FlowerClass::bloom();
It returns: PHP Fatal error: Uncaught Error: Class 'Papillon\Fountaine\Eau\FlowerClass' not found in .../test_package.php:6
Stack trace:
#0 {main}
thrown in .../test_package.php on line 6
I think that the package may not be recognized by the main project; maybe the package was improperly installed in the main project?
Debugging autoload can be very useful to catch errors. Take care with the route paths, the autoload tryed to find the classes files in a path with a lowercase folder when in the package composer.json the route was definded with that folder uppercase.

Composer not autoloading classes in directory with same name

I am using composer to include a private package in my project that will includes some classes I will use to test against with PHPUnit. Most of the package is being autoloaded correctly and I can call the classes from my unit test, however any class that is named the same as the directory it is in is throwing a "Class not found" error.
The repository is conforming to psr-0 and is located at https://github.com/DeschutesDesignGroupLLC/IPS-Source
File structure example throwing error:
--src
----IPS
------DateTime
--------DateTime.php
Calling $date = new \IPS\DateTime; throws an error.
File structure example NOT throwing error:
--src
----IPS
------Http
--------Url.php
Calling $url = new \IPS\Http\Url; does not throw an error.
Composer.json of private package:
{
"name": "deschutesdesigngroupllc/ips",
"description": "Invision power board source files used to test against",
"homepage": "https://www.invisioncommunity.com",
"version": "4.3.6",
"autoload": {
"psr-0": {
"IPS\\": "src/"
}
},
"extra": {
"branch-alias": {
"dev-master": "4.3.6"
}
},
"require": {
"phpdocumentor/phpdocumentor": "dev-master"
}
}
In the first example, you want a file yet you give the path to it's parent. In the second, you again want a file, but this time supply the full path. Unsurprisingly, the first fails and the second succeeds.
It would appear that
$date = new \IPS\DateTime\DateTime;
is what you intended to ask for.

Fatal Error: Class not Found when using namespaces

I have been trying to use namespaces for the first time in ages and I am running into the below problem. I am currently using Composer for a PSR-4 autoloader and I keep getting the error:
Fatal error: Class 'API\Library\Config' not found in C:\wamp64\www\project\src\index.php on line 14
composer.json
"autoload": {
"psr-4": {
"API\\": "src",
"API\\Library\\": "src/Library",
"API\\Controllers\\": "src/Application/Controllers"
}
}
src/index.php
namespace API;
include_once('vendor/autoload.php');
use API\Library\Config;
$config = new Config(); //line 18
The Folder layout is as such:
Its because src is the parent folder. Ideally vendor would be in the same directory as src.
"autoload": {
"psr-4": {
"API\\": "",
"API\\Library\\": "Library",
"API\\Controllers\\": "Application/Controllers"
}
}
Would work, or you should restructure your directories.
Also you can leave out "API\\Library\\": "Library", as it will be picked up by "API\\": "",

Issue with Composer's Autoloader

I'm starting work on a new mini-framework project, which I have in a local GIT repo on my machine. I've set up a test project that pulls in the local repo via Composer, however the autoloader isn't working as expected (Fatal Error: Class X not found errors). This is the first time I've used autoloading outside of what is automatically generated (e.g. when using an existing framework) and despite reading around, I can't seem to solve this.
Package
In an attempt to get this working, the package only contains a src directory with a single App.php class on top of the composer.json file in the root.
composer.json
{
"name": "myvendor/framework",
"description": "Framework Description",
"license": "MIT",
"authors": [
{
"name": "Joe Bloggs",
"email": "joe#email.com"
}
],
"autoload": {
"psr-0": {
"Framework": "src/"
}
}
}
Project
composer.json
{
"repositories": [
{
"type": "vcs",
"url" : "../Framework"
}
],
"require": {
"myvendor/framework": "dev-master"
}
}
This successfully clones the local repo and adds the code to the vendor directory.
The namespace is also successfully added to Composer's autoload_namespaces.php file like so;
vendor/composer/autoload_namespaces.php
'Framework' => array($vendorDir . '/myvendor/framework/src'),
When I attempt to load the App class however using the following code, I get the error;
web/index.php
<?php
require_once '../vendor/autoload.php';
$app = new \Framework\App();
You're using the psr-0 specification for the class loader. This means that the full namespace has to be visible in the file structure. The prefix only tells the autoloader were to look for this namespace.
So in your case, you configured that the "Framework" namespace is available in the "src/" directory. This means that the class \Framework\App should life in src/Framework/App.php. In your case, it exists in src/App.php. This means that the autoloader cannot find your class.
However, there is a class loader specification that does what you want: psr-4. This is also the recommended specification (psr-0 might be removed in the future). With PSR-4, the file structure only includes the namespaces after the configured prefixes. So when doing "psr-4": { "Framework\": "src/" }, a class called \Framework\App should life in src/App.php and a class called \Framework\Some\Special\App should life in src/Some/Special/App.php.

Test my own composer package does not work

I want to make a composer package. However, I am still in the development phase, would or would but the earlier test out.
I have an empty vendor folder with the autoloader from composer:
/vendor
/composer
autoload.php
So now I've tried my package "simulate" and creates my folder structure and composer.json:
/vendor
/composer
/me
/package
/src
/tests
composer.json
autoload.php
This is my composer.json:
{
"name": "me/package",
"description": "",
"license": "",
"authors": [
{
"name": "",
"email": ""
}
],
"minimum-stability": "dev",
"require": {
"php": ">=5.4.0"
},
"autoload": {
"psr-4": {
"Me\\Package\\": "src/"
}
}
}
And here is my class:
namespace Me\Package;
class Test {
// ...
}
If I want to call it:
if(file_exists('vendor/autoload.php')) require 'vendor/autoload.php';
$test = new \Me\Package\Test();
i become Fatal error: Class 'Me\Package\Test' not found.
Of course, I also inserted a composer.json in the root directory, but I can still bad at require my package state since it was not published, right? But how do I test it then and say to composer he should autoload my package?
If you want to use composer to include a package that is not listed on http://Packagist.org/ you would add a 'repositories' stanza into the composer.json (project root file). This reads the project, and gets the composer.json from it, using the name for the main-'requires' section.
"repositories": [
{
"type": "vcs",
"url": "https://github.com/example/private-repo.git"
}
}
The 'url' part, can also in fact be any valid URL for a git, SVN or HG repository - even a file:// based reference.

Categories