Dependency Injection in PHP: A Practical Guide
Q: How do you handle dependency injection in PHP? Can you provide a practical example of its implementation?
- PHP
- Senior level question
Explore all the latest PHP interview questions and answers
ExploreMost Recent & up-to date
100% Actual interview focused
Create PHP interview for FREE!
Dependency Injection (DI) in PHP is a design pattern used to implement IoC (Inversion of Control), allowing us to achieve greater modularity and testability in our code. The core idea is to pass the dependencies of a class as parameters, rather than having the class instantiate them itself. This promotes loose coupling between components.
There are several ways to implement dependency injection: constructor injection, setter injection, and interface injection. In this example, I'll demonstrate constructor injection.
Let's assume we have a simple application that uses a `UserRepository` class to fetch user data and a `UserService` class that processes user-related logic.
First, we'll define the `UserRepository` interface:
```php
interface UserRepositoryInterface {
public function find($id);
}
```
Next, we'll implement this interface in a `DatabaseUserRepository` class:
```php
class DatabaseUserRepository implements UserRepositoryInterface {
public function find($id) {
// Simulating a database call
return "User data for ID: " . $id;
}
}
```
Now, we create the `UserService` that depends on the `UserRepositoryInterface`:
```php
class UserService {
private $userRepository;
public function __construct(UserRepositoryInterface $userRepository) {
$this->userRepository = $userRepository;
}
public function getUser($id) {
return $this->userRepository->find($id);
}
}
```
Finally, to use these classes effectively with dependency injection, we can do the following in our application:
```php
// Dependency Injector
$userRepository = new DatabaseUserRepository();
$userService = new UserService($userRepository);
// Fetching user data
echo $userService->getUser(1);
```
In this example, we’ve injected the `DatabaseUserRepository` dependency into the `UserService` constructor. This approach allows us to easily swap out the `DatabaseUserRepository` for another implementation (e.g., `ApiUserRepository`) if needed, without modifying the `UserService`. This makes our code more flexible and easier to test, as we can create mock implementations of the `UserRepositoryInterface` for unit testing.
There are several ways to implement dependency injection: constructor injection, setter injection, and interface injection. In this example, I'll demonstrate constructor injection.
Let's assume we have a simple application that uses a `UserRepository` class to fetch user data and a `UserService` class that processes user-related logic.
First, we'll define the `UserRepository` interface:
```php
interface UserRepositoryInterface {
public function find($id);
}
```
Next, we'll implement this interface in a `DatabaseUserRepository` class:
```php
class DatabaseUserRepository implements UserRepositoryInterface {
public function find($id) {
// Simulating a database call
return "User data for ID: " . $id;
}
}
```
Now, we create the `UserService` that depends on the `UserRepositoryInterface`:
```php
class UserService {
private $userRepository;
public function __construct(UserRepositoryInterface $userRepository) {
$this->userRepository = $userRepository;
}
public function getUser($id) {
return $this->userRepository->find($id);
}
}
```
Finally, to use these classes effectively with dependency injection, we can do the following in our application:
```php
// Dependency Injector
$userRepository = new DatabaseUserRepository();
$userService = new UserService($userRepository);
// Fetching user data
echo $userService->getUser(1);
```
In this example, we’ve injected the `DatabaseUserRepository` dependency into the `UserService` constructor. This approach allows us to easily swap out the `DatabaseUserRepository` for another implementation (e.g., `ApiUserRepository`) if needed, without modifying the `UserService`. This makes our code more flexible and easier to test, as we can create mock implementations of the `UserRepositoryInterface` for unit testing.


