Insights into Company
← PHP & Laravel

Composer and Dependency Injection

Understand the idea. Compare it. Explain it. Test yourself.

Question 1 of 8

What is Composer?

Practice question · write your own answer
  • Define the concept in one or two sentences.
  • Give a small example and trace what happens.
  • Explain one limitation, trade-off, or common mistake.
Practice explaining this
Question 2 of 8

What is the difference between composer.json and composer.lock?

Practice question · write your own answer
  • Define the concept in one or two sentences.
  • Give a small example and trace what happens.
  • Explain one limitation, trade-off, or common mistake.
Practice explaining this
Question 3 of 8

Why should composer.lock be committed?

Practice question · write your own answer
  • Define the concept in one or two sentences.
  • Give a small example and trace what happens.
  • Explain one limitation, trade-off, or common mistake.
Practice explaining this
Question 4 of 8

What is PSR-4 autoloading?

Practice question · write your own answer
  • Define the concept in one or two sentences.
  • Give a small example and trace what happens.
  • Explain one limitation, trade-off, or common mistake.
Practice explaining this
Question 5 of 8

What is dependency injection?

Solution and explanation

  • Dependency injection means a class receives its dependencies instead of creating them internally.
  • Bad approach: the controller is tightly coupled to PaymentService.
class OrderController
{
    public function createOrder()
    {
        $payment = new PaymentService();
        $payment->process();
    }
}
  • Better approach: constructor injection, resolved by the service container.
class OrderController
{
    public function __construct(private PaymentService $paymentService) {}

    public function createOrder()
    {
        $this->paymentService->process();
    }
}
  • Interface example:
interface PaymentGateway
{
    public function pay(float $amount);
}

class RazorpayGateway implements PaymentGateway
{
    public function pay(float $amount)
    {
        // Razorpay implementation
    }
}

// In a service provider's register():
$this->app->bind(PaymentGateway::class, RazorpayGateway::class);

class PaymentService
{
    public function __construct(private PaymentGateway $gateway) {}
}
  • The service doesn't care whether payment goes through Razorpay, Stripe or another gateway.
  • That is loose coupling, and in tests you can bind a fake gateway.
Practice explaining this
Question 6 of 8

How does Laravel resolve dependencies from its service container?

Solution and explanation

  • A very important 5-year question.
  • The service container manages class dependencies and performs dependency injection.
class PaymentService
{
    public function process()
    {
        //
    }
}

class OrderController extends Controller
{
    public function __construct(private PaymentService $paymentService) {}
}
  • Laravel automatically resolves PaymentService from the container when it builds the controller.
  • Why it is useful: dependency injection, loose coupling, testability, interface-to-implementation binding and centralized dependency management.
Practice explaining this
Question 7 of 8

What is constructor injection?

Solution and explanation

  • Dependency injection means a class receives its dependencies instead of creating them internally.
  • Bad approach: the controller is tightly coupled to PaymentService.
class OrderController
{
    public function createOrder()
    {
        $payment = new PaymentService();
        $payment->process();
    }
}
  • Better approach: constructor injection, resolved by the service container.
class OrderController
{
    public function __construct(private PaymentService $paymentService) {}

    public function createOrder()
    {
        $this->paymentService->process();
    }
}
  • Interface example:
interface PaymentGateway
{
    public function pay(float $amount);
}

class RazorpayGateway implements PaymentGateway
{
    public function pay(float $amount)
    {
        // Razorpay implementation
    }
}

// In a service provider's register():
$this->app->bind(PaymentGateway::class, RazorpayGateway::class);

class PaymentService
{
    public function __construct(private PaymentGateway $gateway) {}
}
  • The service doesn't care whether payment goes through Razorpay, Stripe or another gateway.
  • That is loose coupling, and in tests you can bind a fake gateway.
Practice explaining this
Question 8 of 8

When should you bind an interface to an implementation?

Solution and explanation

  • Dependency injection means a class receives its dependencies instead of creating them internally.
  • Bad approach: the controller is tightly coupled to PaymentService.
class OrderController
{
    public function createOrder()
    {
        $payment = new PaymentService();
        $payment->process();
    }
}
  • Better approach: constructor injection, resolved by the service container.
class OrderController
{
    public function __construct(private PaymentService $paymentService) {}

    public function createOrder()
    {
        $this->paymentService->process();
    }
}
  • Interface example:
interface PaymentGateway
{
    public function pay(float $amount);
}

class RazorpayGateway implements PaymentGateway
{
    public function pay(float $amount)
    {
        // Razorpay implementation
    }
}

// In a service provider's register():
$this->app->bind(PaymentGateway::class, RazorpayGateway::class);

class PaymentService
{
    public function __construct(private PaymentGateway $gateway) {}
}
  • The service doesn't care whether payment goes through Razorpay, Stripe or another gateway.
  • That is loose coupling, and in tests you can bind a fake gateway.
Practice explaining this