How to determine which libraries were loaded by Composer autoload.php - php

Is there a way, within PHP, to get a list of all libraries loaded by Composer's /vendor/autoload.php file?
Example:
require_once("./composer/vendor/autoload.php");
// In some way, get a list of libraries that were loaded:
$libraries = composer_get_libraries(); // you get the idea
I can't seem to find this in the Composer docs or google...
It's easy to list the installed libraries ('composer show') but this doesn't show which ones are autoloaded in PHP. The reason I'm asking is that I just installed a new library with composer require [library name], but in PHP the library's class is not found. I'm trying to debug this problem and it would be helpful to ensure the autoload.php is actually loading this library.
Even enabling a "debugger" option that would dump the autoloader activity to a log file would be helpful.
Update: looking into the When unit test code, I see there must be a
use When\When;
before instantiating a When object.

PHP itself has no notion of a library or a package, only the functions, classes, etc, it defines.
Composer, in turn, has no notion of how the code is being used; it may register one or more autoloaders using the spl_autoload_register function, based on the configuration of the installed packages, but it can also include certain files on every page load, which might register their own autoloader, or just define classes and functions directly.
There is therefore no concept anywhere of "the autoloader loading that library" - there might be a combined PSR-4 autoloader built by Composer, plus a combined classmap autoloader, plus a bunch of custom autoloaders, none of which have any need to "remember" which package they belong to.
When you ask for the class, PHP runs all the autoloaders that are registered, and each has a chance to define the class, usually by including a file.
All of this happens in PHP code, so a debugger such as XDebug can be used to see what autoloaders are actually run, and what each does, but beware that they may be hard-to-read machine-generated code.
A class not being autoloaded suggests one of three things:
Composer has not generated the correct autoloader code. You might try running composer dump-autoload
The package contains incorrect autoload information in its composer.json. This is unlikely unless nobody else has installed it using Composer.
You have made a mistake in the way you referenced the class, for instance missing the namespace, or mistyping it in a use statement.

Related

Loading and using PHP class without namespace and without using 'use'

Is it possible to create a package for a class without a namespace, and instantiate it in my scripts without using the language construct use?
eg:
<?php
require_once 'vendor/autoload.php';
// use \Something_MyClass; (I don't want to use this 'use')
$mc = new MyClass(); // instead of $mc = new Something\MyClass()
?>
Copy of my comment below, just to clarify:
"This is because I am still using php 5.2. For legacy reasons I can't upgrade php to 5.3 or beyond. I can't use namespacing, but I want to use composer for autoloading and dependency manageament."
It's not possible.
Even if you register with spl_autoload_register a function that, upon new MyClass(), will include a file with class Something_MyClass, that same line will fail, because you're trying to instantiate a class that doesn't exist.
Your best course of action is to upgrade your PHP to 5.3 (although the lowest supported version as of now is 7.1, and I highly recommend going there). You could, of course, create your own package manager (as YvesLeBorg suggested in comments), but that will get you even deeper into legacy, and make it even harder to maintain and upgrade PHP in the future, not to mention potential bugs and extra maintenance overhead.
You can perfectly use PHP 5.2 syntax in your source code and combine it with Composer, even with Composer PSR-0 autoloading. Composer does not enforce any rules regarding the PHP version.
The only thing that you cannot work around is that Composer itself requires PHP 5.3.2 to run. But everything else is up to you.
In more details, your only option for "namespaced classes" with PHP 5.2 is to use the now dreaded Under_Score_Class_Name variant, which can be autoloaded with PSR-0. You'll always have to use the full classname (use and proper namespaces would allow you to use shorter names). That example classname must reside in the path /Under/Score/Class/Name.php and would be autoloaded with "autoload": {"psr-0": {"Under": "/"}}. You have no way to shorten that path with PSR-0 (one of the reasons PSR-4 was invented), it must always contain every word between underscores as a folder level, starting with the first word. The only thing you can change is that Composer does not require you to use a folder in the main directory of the library. You could use the path src/Under/Score/Class/Name.php and autoload with "psr-0": {"Under_": "src/"}.
Running Composer with a PHP version 5.3.2 or greater probably boils down to a) installing it and then b) explicitly point to this version when running Composer, like /usr/local/bin/php7.2.23/php composer.phar install.
In case you don't want to use long paths, simply using class names in the root namespace is allowed - note however that they must not duplicate existing class names from PHP itself. Without a common class name prefix like Under_ from the example above, your autoloading could be "psr-0": {"": "src/"}. Note however that this tells the Composer autoloader that every class may be found in your library. Composer will keep track of where it found something and not try again anywhere else, but it will still affect performance. So it is best to go with the common prefix.

Call TYPO3 PHP function from outside TYPO3

I try to open an extbase view in a different window.
For this I call the function
\typo3\sysext\extbase\Classes\Mvc\Controller\AbstractController->redirect().
But it fails, due to abstract class AbstractController implements ControllerInterface. It can not find ControllerInterface. It is in the folder, but the folder isn't included in the path get_include_path().
Is there any way to go arround this problem without changing the TYPO3 file?
On the surface this looks like a typical class loading issue, so I'll describe the pitfalls there in case someone comes searching for that type of error and finds this post.
If you installed TYPO3 via composer, make sure you load the composer autoload file from your external file. Composer paths do not appear in the PHP include paths, and you should never have to include any other file than the composer autoload file.
If you did not install via composer you will need to run your script in a TYPO3 context. Only then will class loading work.
That said: the fact that class loading is inactive indicates you are trying to use TYPO3 features completely outside TYPO3. It is no easy task to simply use TYPO3 classes outside of a TYPO3 context - especially not Extbase ones, and especially not controllers. There are so many dependencies on configuration, database and request handling. I would strongly discourage attempting to do this.
Even generating a link to a controller action involves calculating a request hash which in turn requires access to the TYPO3 configuration and database. So in all likelihood, what you are attempting is simply not possible - you need to do it from within a TYPO3 context.

Can individual Composer dependencies be suppressed from (auto)loading?

I have a project containing, amongst others, the following composer.json dependencies:
"propel/propel1": "dev-master"`,
"halleck45/phpmetrics": "dev-master"
I recently did a composer update and found that a new version of a library required by PhpMetrics, called Hoa, introduces a new class \EngineException to emulate a new PHP7 class. Unfortunately Propel 1 also defines \EngineException, and so a conflict results.
The correct fix for this would be to upgrade to Propel 2, which uses namespaces. However this is still in alpha and is subject to BC breaks, so is not really workable for me.
My present fix is to lock Hoa to a specific version that does not have the new class:
"hoa/core": "2.15.04.*"
That's not a bad solution, but it isn't entirely satisfying to lock a library to an old version.
In the Hoa code, the only way for the new class not to be loaded is to be running PHP 7, which is again not feasible. However, it also occurs to me that Hoa only needs to be required when PhpMetrics runs. This is a stand-alone code analysis tool and only sits in the root of the project for convenience; the rest of the project does not use this library.
Thus, it would be great if I could call something in Composer to ask that this class is not (auto)loaded, or perhaps something to do the same in the composer.json. It is being needlessly loaded at present - I don't know whether it is being autoloaded incorrectly or whether it is being required manually by Composer.
It may help to know that Hoa classes have been added by Composer to the auto-generated autoload_psr4.php script. As far as I can understand the docs, this means it is autoloaded, and there is nothing in my project that would require any of the Hoa classes.
Fixed by https://github.com/hoaproject/Core/commit/8ed00fe9345c4f8b2679a256926d6d24994ea842.
The new exception architecture introduced in PHP7 [1] has been totally
redesigned [2]. This patch updates the retro-compatibility classes
according to this new architecture. Consequently, the BaseException
class has been removed, along with EngineException and
ParseException. While these latters could be implemented (not as
is), we prefer to, so far, only implement the Throwable interface.
Let see if we can implement (still for the retro-compatibility) the
Error, TypeError and ParseError class.
[1]: https://wiki.php.net/rfc/engine_exceptions_for_php7
[2]: rfc/throwable-interface
I was curious, so I looked it up. Hoa indeed has a broken approach, having the file Core.php always included, by a "file" autoload in composer which in turn includes Consistency.php. The latter defines your class.
You could raise an issue with the developers at Hoa, to use class_exists to check for the method rather than the currection version check they are using. This could cause the propel autoloader to load its own. Another way would be to define their autoloading correctly, but they prefer to load manually as it seems.

Composer: Require a package with custom namespace

I've been progressively starting to use Composer on my PHP projects, however there's something that I always questioned.
For instance, let's say this is my composer.json file:
{
"require": {
"ramsey/uuid": "~2.8"
}
}
I'm telling composer I want the package ramsey/uuid and as expected it download and includes the package.
When I want to access the classes on the package, I'm forced to something like:
$uuid = \Rhumsaa\Uuid\Uuid::uuid4();
Is there a way I can require the package and force a simpler namespace like for eg. \Uuid::uuid4();, avoiding the need to write the full NS including package author?
What should I change on my composer.json to be able to do this? Thank you.
Note: I'm aware of PHP's use. I could use Rhumsaa\Uuid\Uuid;... However I need to do this in every single file, it's not practical. Even less if I'm putting together a small self-usage framework. I want for instante to have \Util\UUIDmapped to \Rhumsaa\Uuid\Uuid.
I also think the file autoload_psr4.php could be changed to accomplish this, however after an update all changes are discarded.
No, there is nothing you can do to shorten these namespaces.
Composer doesn't have to do anything with PHP namespaces. The name you use to identify the software package is unrelated to the PHP namespace. They don't have to match in any way. Composer only provides an autoloader that will include the source code of a class you are using in your code. The possible alteratives would be to either load that source code manually using include_once() or require_once(), or create an autoloader on your own that does this.
Now that Composer is out of the way, we can discuss namespaces and class names. Before PHP 5.3, there were no namespaces. Classes either were not generally used in multiple projects because they were created with short names that likely would conflict with other classes bearing the same name, or they were extended to contain a distinguishing component in their name, like Zend_Controller_Abstract or sfController (from Symfony 1).
These class names also tend to get very long, especially with the invention of PSR-0 autoloading (which was for a very long time the only PSR standard ever defined).
With namespaces you get at least a method to shorten those class name references in your code.
You have to either use the original, long form in every place you use, or you have to import it with a shorter alias. Yes, you have to repeat the import clause in every file - but you don't import EVERY class into EVERY file, you would only import the classes you actually use.
Using an IDE is very helpful with these tasks. They offer you a way to search in all available classes for the one you want to use but can't remember. They also deal with importing namespaced classes into your file. You'd rarely ever need to manually "add the imports everywhere".

When I auto-load a class/file with composer, what is actually happening behind the scenes?

I haven't been able to find a strait answer to this question yet elsewhere online and was wondering how exactly composer autoloading worked.
When I autoload a class using PSR-0 or classmap what is actually happening behind the scenes? Is it just calling include(or some include variant) on the the specified file in the specified path. Is it actually skimming the file for class definitions and constructing its own file to include? Is it doing something that isn't analogous to a file include?
Thanks in advance!
A PSR-0 autoloader is simply a function attached to the global PHP process with spl_autoload_register(). That registered function is called whenever PHP needs to instantiate a class that isn't yet known, so this is the last moment to make the classes code known before PHP fails.
And the implementation of that autoloading can be either pretty sophisticated, or pretty simple, but in every case it will use either include() or require() (possibly with _once, but this is not really needed) to make the class code known to PHP. You could also implement a call to eval() to dynamically add some code that declares the class needed, but this would just be for academic used - I haven't seen it being used in real cases.
The same applies to the classmap loading. The classmap array contains names of classes as keys, and the filename of the containing file as value. This is for cases where there is no PSR-0-compatible ruleset mapping between class name and file path.
If you want more details of how Composer does the autoloading, you should have a look at the generated files inside vendor/composer. Basic knowledge about how PHP autoloading works in general would help understand what happens there.
Behind the scenes composer use spl_autoload_register to register an autoloader function which include your class.
The registered function follows a standardized namespace/path resolution algorithm (basically consider all "\" or "_" in your class name as path separators from a specified base directory) to find the php file to include.
Also, when you run composer install it create a cached index of relation between paths and namespace to speed up the path resolution.
You can dig in the Github repository and see it for yourself.

Categories