Course outline

Laravel / Basic: request and data foundations / Lesson 1

Request lifecycle and the service container

Follow a request through framework boundaries and make dependencies explicit. Use isolated framework components while distinguishing them from a fully booted Laravel application.

About 4 min readContent reviewed
On this page

Lesson goals

  • Explain bootstrap, routing, middleware, and response ownership.
  • Resolve concrete and interface dependencies deliberately.
  • State the course framework and runtime baseline.

A verified baseline is narrower than a latest-version claim

This course targets Laravel 12 and PHP 8.3-compatible syntax. Local component examples are validated using installed laravel/framework 12.63.0 on PHP 8.5.12 CLI, without loading the project bootstrap or environment. As reviewed on 2026-10-25, Laravel 12 is in security-fixes-only support through 2027-02-24 according to its official schedule. That is a teaching baseline, not a recommendation to start every new application on this version. Recheck support, PHP compatibility, and dependency constraints when choosing a deployment runtime. Documentation and skeleton layout can differ between major versions, so identify the version before copying a configuration example.

Follow ownership from entry point to response

A web entry point creates and bootstraps the application, receives an HTTP request, passes it through middleware and routing, and sends the resulting response. Service providers register framework and application capabilities; controllers coordinate use cases rather than manually rebuilding every facility. Different execution paths, such as Artisan commands and queue workers, have different lifetimes and entry conditions. A framework component instantiated in a CLI fixture does not automatically run web middleware, authentication, exception rendering, or session cookies. Keep those missing boundaries visible so a small passing example is not reported as complete application behavior.

The container resolves a dependency graph

The service container can construct many concrete classes by reflecting their constructor dependencies. Interfaces need a deliberate binding because the framework cannot infer which implementation represents the application policy. Prefer explicit constructor dependencies over asking a global container for arbitrary services inside domain logic. The example resolves a pricing policy and a quote service in a new container, with no application or database. It establishes dependency wiring only. A real service still needs validated input, meaningful errors, and a clear owner for external effects. Automatic construction does not make an unclear contract correct.

php An isolated container resolves an explicit interface binding
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
interface PricePolicy { public function apply(int $cents): int; }
final class FixedPolicy implements PricePolicy { public function apply(int $cents): int { return $cents - 100; } }
final class QuoteService {
    public function __construct(private PricePolicy $policy) {}
    public function quote(int $cents): int { return $this->policy->apply($cents); }
}
$container = new Illuminate\Container\Container();
$container->bind(PricePolicy::class, FixedPolicy::class);
echo $container->make(QuoteService::class)->quote(500), PHP_EOL;
Expected output
400

The result demonstrates local construction and policy use. It does not bootstrap providers or validate a real pricing system.

Bindings have lifetimes as well as types

A transient binding can produce a fresh instance on each resolution, while a singleton retains one instance in that container. Scoped bindings align with defined application lifecycles where supported. Avoid putting request-specific user or tenant state into a singleton used by a long-lived worker; stale state can cross jobs or requests. The local identity comparison makes the distinction observable without running a worker. Use a singleton for a genuinely shared dependency with appropriate state rules, not merely to save a constructor call. Test disposal and repeated resolution when mutable state is involved.

php Transient and singleton identity in one owned container
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
final class Marker {}
$container = new Illuminate\Container\Container();
$container->bind('fresh', fn() => new Marker());
$container->singleton('shared', fn() => new Marker());
echo $container->make('fresh') === $container->make('fresh') ? "same\n" : "different\n";
echo $container->make('shared') === $container->make('shared') ? "same\n" : "different\n";
Expected output
different
same

The comparison concerns this container only. Request scoping and worker reset behavior need their own integration evidence.

Keep framework integration at explicit edges

A useful application separates HTTP parsing, authorization, domain decisions, persistence, and response rendering. Laravel supplies adapters and conventions, but their presence does not eliminate those responsibilities. Keep pure rules testable without facade state, and test framework integration where routing, providers, and middleware matter. Record the actual container, configuration, and storage assumptions for each example. Never execute the real project bootstrap to make a teaching snippet convenient; an isolated fixture can bind exactly what the example needs. This makes failures easier to interpret and prevents accidental use of configured services or secrets.

Common errors and fixes

A missing interface binding is blamed on routing

Why it happens
Construction failure and request matching are conflated.
How to fix it
Inspect the constructor graph and bind the intended implementation.
Prevent it next time
Test container resolution separately from HTTP dispatch.

A singleton retains a previous user context

Why it happens
Request-specific state outlives its intended owner.
How to fix it
Use appropriate lifecycle scope or explicit per-operation input.
Prevent it next time
Test repeated jobs and request boundaries with synthetic identities.

A component test is claimed as a full web test

Why it happens
Missing middleware and bootstrap assumptions are hidden.
How to fix it
State the tested layer and add isolated integration evidence.
Prevent it next time
Label each exampleโ€™s host and omitted boundaries.

Check your understanding

1. A service accepts a repository interface. What must the container know?

Show worked solution

It needs an explicit mapping from that interface to the intended implementation or factory, plus resolvable dependencies for that implementation. Bind a synthetic in-memory implementation in a local test rather than loading application configuration. Construction success alone does not establish persistence correctness.

2. Why is a current learner identifier a poor singleton property?

Show worked solution

The object can outlive the request or job that supplied the identifier, exposing stale context to later work. Pass the identifier as explicit validated input or use a lifecycle-bound context that is reset correctly. Test consecutive synthetic operations, not only the first resolution.

Key takeaways

  • The container wires dependencies; application contracts still own meaning.
  • Version, host, and lifecycle assumptions belong with the evidence.

Official references