The `php-fig/container` package is a meta-package that provides the interfaces defined by PSR-11: Container Interface. PSR-11 is a standard for interoperability among Dependency Injection (DI) containers in the PHP ecosystem. It does not provide a concrete implementation of a DI container itself, but rather a set of common interfaces that any compliant DI container must adhere to.
The primary goal of PSR-11 and `php-fig/container` is to solve the problem of vendor lock-in when choosing a DI container. By standardizing the way applications retrieve services from a container, developers can switch between different PSR-11 compliant container implementations (e.g., Symfony DependencyInjection, PHP-DI, League/Container, Pimple) without having to refactor their application's codebase extensively.
Key interfaces provided by `php-fig/container` (all residing in the `Psr\Container` namespace):
1. `ContainerInterface`: This is the core interface. It defines two methods:
* `get(string $id)`: Finds an entry of the container by its identifier and returns it. If the identifier is not found, it *must* throw a `NotFoundExceptionInterface`.
* `has(string $id)`: Returns `true` if the container can return an entry for the given identifier, `false` otherwise.
2. `NotFoundExceptionInterface`: This interface *must* be implemented by an exception thrown when calling `get()` with an identifier that does not exist in the container. It extends `Psr\Container\ContainerExceptionInterface`.
3. `ContainerExceptionInterface`: This is a general exception interface that *must* be implemented by any exception thrown by a container. It serves as a base interface for all container-related exceptions.
Benefits of using `php-fig/container` (and PSR-11):
* Interoperability: Code written to use `Psr\Container\ContainerInterface` can work with any PSR-11 compliant container implementation.
* Portability: Applications and libraries become more portable across different frameworks or environments that might use different DI containers.
* Decoupling: Promotes loosely coupled architectures by standardizing how dependencies are resolved, making components less dependent on a specific container implementation.
* Testability: Makes it easier to mock or replace the container or its services during testing.
In essence, `php-fig/container` acts as a contract. Any library or framework can depend on this contract, ensuring that its users can choose their preferred PSR-11 compliant DI container without compatibility issues.
Example Code
```php
<?php
// To run this example, you would typically install Composer and then run:
// composer require php-fig/container league/container
// 'league/container' is chosen here as a simple, PSR-11 compliant implementation.
require 'vendor/autoload.php';
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
use League\Container\Container as LeagueContainer;
use League\Container\Argument\Literal\StringArgument;
// --- 1. Define some example services and dependencies ---
// An interface for a logging service
interface LoggerInterface
{
public function log(string $message): void;
}
// A concrete implementation of the logger
class ConsoleLogger implements LoggerInterface
{
private string $prefix;
public function __construct(string $prefix = "LOG")
{
$this->prefix = $prefix;
}
public function log(string $message): void
{
echo "[" . $this->prefix . "] " . $message . "\n";
}
}
// A service that depends on a LoggerInterface and a database connection string
class UserService
{
private LoggerInterface $logger;
private string $dbConnection;
public function __construct(LoggerInterface $logger, string $dbConnection)
{
$this->logger = $logger;
$this->dbConnection = $dbConnection;
}
public function createUser(string $name): void
{
$this->logger->log("Attempting to create user '" . $name . "' using DB: " . $this->dbConnection);
// ... imagine database operations here
echo "User '" . $name . "' created successfully.\n";
}
}
// --- 2. Instantiate a PSR-11 compliant container ---
// Here, we use League\Container as an example implementation.
$container = new LeagueContainer();
// --- 3. Register services with the container ---
// Register a simple scalar value (e.g., a configuration parameter)
$container->add('database.connection_string', 'mysql:host=localhost;dbname=my_app_db');
// Register the LoggerInterface with its concrete implementation (ConsoleLogger).
// We can specify constructor arguments directly.
$container->add(LoggerInterface::class, ConsoleLogger::class)
->addArgument(new StringArgument('APP_EVENT')); // Pass 'APP_EVENT' as the prefix to ConsoleLogger's constructor
// Register the UserService. The container will automatically resolve its dependencies
// based on type hints and registered services.
$container->add(UserService::class)
->addArgument(LoggerInterface::class) // This tells the container to inject the service registered for LoggerInterface
->addArgument('database.connection_string'); // This tells the container to inject the string service 'database.connection_string'
// --- 4. Use the container (which implements Psr\Container\ContainerInterface) to retrieve services ---
echo "--- Retrieving Services ---\n";
// Check if a service exists before retrieving it
if ($container->has(LoggerInterface::class)) {
/ @var LoggerInterface $logger */
$logger = $container->get(LoggerInterface::class);
$logger->log("Logger service successfully retrieved from container.");
} else {
echo "Logger service not found.\n";
}
// Retrieve the UserService. Its dependencies will be automatically injected by the container.
/ @var UserService $userService */
$userService = $container->get(UserService::class);
$userService->createUser("Alice Smith");
// Retrieve a simple value by its identifier
$dbConn = $container->get('database.connection_string');
echo "Retrieved DB Connection String: " . $dbConn . "\n";
// --- 5. Demonstrate error handling for non-existent services ---
echo "\n--- Error Handling ---\n";
$nonExistentServiceId = 'NonExistentService';
if (!$container->has($nonExistentServiceId)) {
echo "Container reports that service '" . $nonExistentServiceId . "' does not exist.\n";
try {
// Attempting to get a non-existent service will throw an exception
$container->get($nonExistentServiceId);
} catch (NotFoundExceptionInterface $e) {
// Catching the specific PSR-11 NotFoundExceptionInterface
echo "Caught expected NotFoundExceptionInterface: " . $e->getMessage() . "\n";
} catch (Psr\Container\ContainerExceptionInterface $e) {
// This is a broader catch for any container-related exception
echo "Caught general ContainerExceptionInterface: " . $e->getMessage() . "\n";
}
}
```








php-fig/container