Class not found, apparently. I've tried various things but nothing works.
Composer:
"autoload": {
"psr-4": {
"App\\": "application/"
}
}
File structure:
https://i.imgur.com/h9wOEqI.png
<?php
namespace App\Library\Classes;
defined('START') or exit('We couldn\'t process your request right now.');
class Application
{
private static $libraries = array();
public static function get($library) {
if (isset(self::$libraries[$library]) && isset(self::$classes[$library])) {
return self::$libraries[$library];
}
$fixedLibrary = str_replace('.', '/', $library);
$file = ROOT . '/application/library/classes/' . strtolower($fixedLibrary) . '.php';
self::$libraries[$library] = $library;
$declared = get_declared_classes();
$workingClass = end($declared);
self::$libraries[$library] = new $workingClass();
return self::$libraries[$library];
}
}
?>
Error is on this line:
Application::get('test')->test();
Yet, if I change it to this, it works:
include ROOT . '/application/Library/Application.php';
App\Library\Classes\Application::get('test')->test();
The PSR4 is not built-in part or PHP, you need an implementation of autoloader to use this standard such as provided by the Composer.
When you install or update depedencies, composer generates the relevant code of autoloading, but you can directly update it by the command dump-autoload, as #jibsteroos said. Next you should explicitly include the file vendor/autoload.php in the entry point of your application.
Also, error message says about class Application, but you should add the use statement at first:
use App\Library\Classes\Application;
Application::get('test')->test();
Or use the fully qualified class name (class name with namespace prefix):
\App\Library\Classes\Application::get('test')->test();
Related
I'm working with a old project. Classies have no namespacies.
Path structure:
-container // Container
--app
----model // all classies without namespace
----model_common // all classies used by other two projects without namespace
------Rede // new librarie with namespace
--------Exception
--------Service
----view
----controller
spl_autoload_register function is in a file named init_client.php, inside app path:
define('M_CMN', CLI_APP. 'model_common/'); // $_SERVER['DOCUMENT_ROOT'] . '/app/model_common/'
define('M_CLI', CLI_APP. 'model/'); // $_SERVER['DOCUMENT_ROOT'] . '/app/model/'
function autoload_client($class){
$path_and_class = str_replace('\\', DIRECTORY_SEPARATOR, $class); // May case there is a namespace
if (file_exists(M_CMN . "{$path_and_class}.php")): // First local to find class
require_once M_CMN . "{$path_and_class}.php";
elseif (file_exists(M_CLI . "{$path_and_class}.php")):
require_once M_CLI . "{$path_and_class}.php";
else :
ErrorFunction("Class {$path_and_class} was not found.",ERROR_1);
endif;
}
spl_autoload_register('autoload_client');
Example:
$consult = new DealConsult; // app/model
$consult->checkTransaction('123') // It will use Rede\Store, Rede\Environment and Rede\eRede classies
Error: Class Rede/Store was not found. But file $_SERVER['DOCUMENT_ROOT'] . '/app/model/Rede/Store.php' exist.
DealConsult.php class:
use Rede\Store;
use Rede\Environment;
use Rede\eRede;
class DealConsult {
public function checkTransaction($cod) {
$this->store = new Rede\Store($_SESSION['trans']['id_filiacao'], $_SESSION['trans']['token'], Rede\Environment::sandbox());
$this->transaction = (new Rede\eRede($this->store))->getByReference($cod);
printf("Autorization status: %s\n", $this->transaction->getAuthorization()->getStatus());
}
What am I not getting understand? I'm learning namespacies recently as well as PSR-4 defaults.
Use Composer to automatically load all the classes. In your composer.json file, you need to have:
{
"autoload": {
"psr-4": {
"Rede\\": "container/app/model_common/"
// Add as many classes as you need here in this map...
}
}
}
After that, run:
compose dump-autoload --optimize
Finally, include vendor/autoload.php where necessary.
I am trying to load a php namespace into my symfony project but keep getting the following error at runtime.
Attempted to load class "FM" from namespace "VehicleTracking\Src\Vendors\FM".
Did you forget a "use" statement for another namespace?
The controller that it is being called from
namespace BWT\FMBundle\Controller;
use VehicleTracking\Src\Vendors\FM\FM;
class FMController extends Controller
{
/**
* #Route("/fuel_data", name="fuelData")
* #return \Symfony\Component\HttpFoundation\Response
*/
public function fuelDataAction(Request $request)
{
//...
$tripProcesses = new FM(); //<-this is the line where I get the error
$_results = $tripProcesses->getTripWithTotals($form->get('fleetNo')->getData(), $form->get('startDate')->getData(), $form->get('endDate')->getData());
}
}
The FM.php file. which is in the directory vendor/bwt/vehicle_tracking/src/vendors
tracking.interface and tracking.class are in the same directory
<?php
namespace VehicleTracking\Src\Vendors\FM;
// : Includes
include_once (dirname(realpath(__FILE__)) . DIRECTORY_SEPARATOR . 'tracking.interface');
include_once (dirname(realpath(__FILE__)) . DIRECTORY_SEPARATOR . 'tracking.class');
// : End
use VehicleTracking\Src\Vendors\Vendors as Vendors;
use VehicleTracking\Src\Vendors\TrackingInterface as TrackingInterface;
class FM extends Vendors\Vendors implements TrackingInterface\TrackingInterface
{
public function getTrackingData()
{...}
}
autoload_namespace.php
<?php
// autoload_namespaces.php #generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
//...
'' => array($vendorDir . '/bwt/vehicle_tracking/src/vendors'),
);
We eventually solved this by adding
"autoload" : {
"psr-4" : {
"Vendors\\" : "src/"
}
},
to the composer.json of the external package and changed the namespace of the classes to namespace Vendors; so that it would be the same as the directory.
I have to run composer update -o to optimise the autoloader otherwise I keep getting these errors.
As a rule you should avoid editing anything under vendor. Your changes will be lost. In this case you can edit your projects composer.json file
"autoload": {
"psr-4": {
"": "src/",
"VehicleTracking\\Src\\Vendors\\FM\\": "vendor/bwt/vehicle_tracking/src/vendors"
},
After making changes, run composer dump-autoload to update the autoload stuff.
The path I gave is based on your question, at least that was the intent. It assumes that FM.php is located directly under vendor/bwt/vehicle_tracking/src/vendors
I only tested a fake FM.php class. That fact that there are include statements in there and some other strange code might generate additional errors.
I'm new to PHP and not really familiar with using git.
I got this library:
https://github.com/CKOTech/checkout-php-library
and I wanna run the sample code here:
https://github.com/CKOTech/checkout-php-library/wiki/Tokens
I know the code may not work perfectly for you cuz you would need a secret key from the provider, however, I don't need general errors like " cannot find class ApiClient"
what I did is simply including the autoloader in my index.php file, is that all what I have to do to use an Autoloader? does it have to do anything with composer.json?
Thanks a ton for the help in advance.
Autoloader.php:
<?php
function autoload($className)
{
$baseDir = __DIR__;
$realClassName = ltrim($className, '\\');
$realClassName = str_replace('\\',DIRECTORY_SEPARATOR,$realClassName );
$fileName = '';
$includePaths = $baseDir.DIRECTORY_SEPARATOR.$realClassName. '.php';
if ( $file = stream_resolve_include_path($includePaths) ) {
if (file_exists($file)) {
require $file;
}
}elseif(preg_match('/^\\\?test/', $className)) {
$fileName = preg_replace('/^\\\?test\\\/', '', $fileName);
$fileName = 'test' . DIRECTORY_SEPARATOR . $fileName;
include $fileName;
} else {
$classNameArray = explode('_', $className);
$includePath = get_include_path();
set_include_path($includePath);
if (!empty($classNameArray) && sizeof($classNameArray) > 1) {
if (!class_exists('com\checkout\packages\Autoloader')) {
include 'com'.DIRECTORY_SEPARATOR.'checkout'.DIRECTORY_SEPARATOR.'packages'.DIRECTORY_SEPARATOR.'Autoloader.php';
}
}
}
}
spl_autoload_register('autoload');
If you want to use an autoloader to make your life measurably better:
Use namespaces/PSR4.
Use Composer.
So let's say I'm working on project foo, within my working directory [let's just say it's /] I make a folder named /src/ and inside is /src/FooClient.php. It contains:
<?php
namespace sammitch\foo;
class FooClient {}
While in / I run composer init and accept all of the defaults, because typing out the simple JSON config file that that generates is tedious. Now I have a composer.json that looks like:
{
"name": "Sammitch/foo",
"authors": [
{
"name": "Sammitch",
"email": "sammitch#sam.mitch"
}
],
"require": {}
}
All we need to do now is add a section to the end:
"autoload": {
"psr-4": {
"sammitch\\foo\\": "src/"
}
}
Now to make Composer do it's magic and make the autoloader just run composer dumpautoload. When this runs Composer will create the /vendor/ folder and the autoloader.
Now all we need to do is:
<?php
require('vendor/autoload.php');
use \sammitch\foo\Client as FooClient()
$c = new FooClient();
Now not only do you have a top-tier autoloader, but you're also set up to start using Composer packages and leveraging all that good stuff from Packagist.
I'm working on a project whereby I have the following file structure:
index.php
|---lib
|--|lib|type|class_name.php
|--|lib|size|example_class.php
I'd like to auto load the classes, class_name and example_class (named the same as the PHP classes), so that in index.php the classes would already be instantiated so I could do:
$class_name->getPrivateParam('name');
I've had a look on the net but can't quite find the right answer - can anyone help me out?
EDIT
Thanks for the replies. Let me expand on my scenario. I'm trying to write a WordPress plugin that can be dropped into a project and additional functionality added by dropping a class into a folder 'functionality' for example, inside the plugin. There will never be 1000 classes, at a push maybe 10?
I could write a method to iterate through the folder structure of the 'lib' folder, including every class then assigning it to a variable (of the class name), but didn't think that was a very efficient way to do it but it perhaps seems that's the best way to achieve what I need?
Please, if you need to autoload classes - use the namespaces and class names conventions with SPL autoload, it will save your time for refactoring.
And of course, you will need to instantiate every class as an object.
Thank you.
Like in this thread:
PHP Autoloading in Namespaces
But if you want a complex workaround, please take a look at Symfony's autoload class:
https://github.com/symfony/ClassLoader/blob/master/ClassLoader.php
Or like this (I did it in one of my projects):
<?
spl_autoload_register(function($className)
{
$namespace=str_replace("\\","/",__NAMESPACE__);
$className=str_replace("\\","/",$className);
$class=CORE_PATH."/classes/".(empty($namespace)?"":$namespace."/")."{$className}.class.php";
include_once($class);
});
?>
and then you can instantiate your class like this:
<?
$example=new NS1\NS2\ExampleClass($exampleConstructParam);
?>
and this is your class (found in /NS1/NS2/ExampleClass.class.php):
<?
namespace NS1\NS2
{
class Symbols extends \DB\Table
{
public function __construct($param)
{
echo "hello!";
}
}
}
?>
If you have an access to the command line, you can try it with composer in the classMap section with something like this:
{
"autoload": {
"classmap": ["yourpath/", "anotherpath/"]
}
}
then you have a wordpress plugin to enable composer in the wordpress cli : http://wordpress.org/plugins/composer/
function __autoload($class_name) {
$class_name = strtolower($class_name);
$path = "{$class_name}.php";
if (file_exists($path)) {
require_once($path);
} else {
die("The file {$class_name}.php could not be found!");
}
}
UPDATE:
__autoload() is deprecated as of PHP 7.2
http://php.net/manual/de/function.spl-autoload-register.php
spl_autoload_register(function ($class) {
#require_once('lib/type/' . $class . '.php');
#require_once('lib/size/' . $class . '.php');
});
I have an example here that I use for autoloading and initiliazing.
Basically a better version of spl_autoload_register since it only tries to require the class file whenever you initializes the class.
Here it automatically gets every file inside your class folder, requires the files and initializes it. All you have to do, is name the class the same as the file.
index.php
<?php
require_once __DIR__ . '/app/autoload.php';
$loader = new Loader(false);
User::dump(['hello' => 'test']);
autoload.php
<?php
class Loader
{
public static $library;
protected static $classPath = __DIR__ . "/classes/";
protected static $interfacePath = __DIR__ . "/classes/interfaces/";
public function __construct($requireInterface = true)
{
if(!isset(static::$library)) {
// Get all files inside the class folder
foreach(array_map('basename', glob(static::$classPath . "*.php", GLOB_BRACE)) as $classExt) {
// Make sure the class is not already declared
if(!in_array($classExt, get_declared_classes())) {
// Get rid of php extension easily without pathinfo
$classNoExt = substr($classExt, 0, -4);
$file = static::$path . $classExt;
if($requireInterface) {
// Get interface file
$interface = static::$interfacePath . $classExt;
// Check if interface file exists
if(!file_exists($interface)) {
// Throw exception
die("Unable to load interface file: " . $interface);
}
// Require interface
require_once $interface;
//Check if interface is set
if(!interface_exists("Interface" . $classNoExt)) {
// Throw exception
die("Unable to find interface: " . $interface);
}
}
// Require class
require_once $file;
// Check if class file exists
if(class_exists($classNoExt)) {
// Set class // class.container.php
static::$library[$classNoExt] = new $classNoExt();
} else {
// Throw error
die("Unable to load class: " . $classNoExt);
}
}
}
}
}
/*public function get($class)
{
return (in_array($class, get_declared_classes()) ? static::$library[$class] : die("Class <b>{$class}</b> doesn't exist."));
}*/
}
You can easily manage with a bit of coding, to require classes in different folders too. Hopefully this can be of some use to you.
You can specify a namespaces-friendly autoloading using this autoloader.
<?php
spl_autoload_register(function($className) {
$file = __DIR__ . '\\' . $className . '.php';
$file = str_replace('\\', DIRECTORY_SEPARATOR, $file);
if (file_exists($file)) {
include $file;
}
});
Make sure that you specify the class file's location corretly.
Source
spl_autoload_register(function ($class_name) {
$iterator = new DirectoryIterator(dirname(__FILE__));
$files = $iterator->getPath()."/classes/".$class_name.".class.php";
if (file_exists($files)) {
include($files);
} else {
die("Warning:The file {$files}.class.php could not be found!");
}
});
do this in a file and called it anything like (mr_load.php)
this were u put all your classes
spl_autoload_register(function($class){
$path = '\Applicaton/classes/';
$extension = '.php';
$fileName = $path.$class.$extension;
include $_SERVER['DOCUMENT_ROOT'].$fileName;
})
;
then create another file and include mr_load.php; $load_class = new BusStop(); $load_class->method()
How can get filesystem path of composer package?
composer.json example:
{
"require" : {
"codeception/codeception" : "#stable",
"willdurand/geocoder": "*"
}
}
example:
$composer->getPath("\Geocoder\HttpAdapter\HttpAdapterInterface");
and return it as:
"/home/me/public_html/vendor/willdurand/geocoder/src/Geocoder/HttpAdapter"
All of this is based on the assumption that you are actually talking about packages and not classes (which are mentioned in the example but are not asked for in the question).
If you have the Composer object, you can get the path of the vendor directory from the Config object:
$vendorPath = $composer->getConfig()->get('vendor-dir');
$vendorPath should now contain /home/me/public_html/vendor/.
It shouldn't be too hard to construct the rest of the path from there, as you already have the package name.
If this feels too flaky or you don't want to write the logic, there is another solution. You could fetch all packages, iterate until you find the right package and grab the path from it:
$repositoryManager = $composer->getRepositoryManager();
$installationManager = $composer->getInstallationManager();
$localRepository = $repositoryManager->getLocalRepository();
$packages = $localRepository->getPackages();
foreach ($packages as $package) {
if ($package->getName() === 'willdurand/geocoder') {
$installPath = $installationManager->getInstallPath($package);
break;
}
}
$installPath should now contain /home/me/public_html/vendor/willdurand/geocoder
Try ReflectionClass::getFileName - Gets the filename of the file in which the class has been defined.
http://www.php.net/manual/en/reflectionclass.getfilename.php
Example:
$reflector = new ReflectionClass("\Geocoder\HttpAdapter\HttpAdapterInterface");
echo $reflector->getFileName();
Or you may use this:
$loader = require './vendor/autoload.php';
echo $loader->findFile("\Geocoder\HttpAdapter\HttpAdapterInterface");
The first method try to load class and return loaded class path. The second method return path from composer database without class autoload.
Here is my solution to get the vendor path without using the $composer object :
<?php
namespace MyPackage;
use Composer\Autoload\ClassLoader;
class MyClass
{
private function getVendorPath()
{
$reflector = new \ReflectionClass(ClassLoader::class);
$vendorPath = preg_replace('/^(.*)\/composer\/ClassLoader\.php$/', '$1', $reflector->getFileName() );
if($vendorPath && is_dir($vendorPath)) {
return $vendorPath . '/';
}
throw new \RuntimeException('Unable to detect vendor path.');
}
}
Not sure if the following is the correct way for this because composer is changing so fast.
If you run this command:
php /path/to/composer.phar dump-autoload -o
it will create a classmap array in this file
vender/composer/autoload_classmap.php
with this format "classname" => filepath.
So to find filepath of a given class is simple. If you create the script in your project's root folder, you can do this:
$classmap = require('vender/composer/autoload_classmap.php');
$filepath = $classmap[$classname]?: null;