Skip to content

AOP Sample Application

Build an app that guards a REST endpoint with a custom AOP attribute. You annotate the endpoint method with #[RequireCustomHeader] and the framework runs your interceptor before the method body: requests carrying X-Custom-Foo-Bar: foo-bar go through, everything else is denied with 403 without the method executing. It applies the concepts from AOP — attributes, interceptors, and the advice lifecycle — in a complete runnable app.

You need PHP 8.5 or later with the winter_boot, swoole, and pcntl extensions (see the Installation guide). No external services are needed.

The sample uses this layout:

aop-guard/
├── bin/
│ └── application.php # Application entry point
├── config/
│ └── application.yml # Server and app identity
├── src/
│ ├── AopSampleApplication.php # Main application class
│ ├── aop/
│ │ ├── RequireCustomHeader.php # The AOP attribute
│ │ └── RequireCustomHeaderInterceptor.php # The advice
│ └── rest/
│ └── AopDemoController.php # Guarded endpoint
└── composer.json # Dependencies

Install the framework package as described in the Installation guide (Docker is recommended).

Switch between the source files. Each tab shows the exact file from the sample.

The single entry point. No extra #[Enable*] attribute is needed — AOP support is always on.

<?php
namespace dev\example;
use dev\winterframework\stereotype\WinterBootApplication;
#[WinterBootApplication(
configDirectory: [__DIR__ . "/../config"],
scanNamespaces: [
['dev\\example', __DIR__ . '']
]
)]
class AopSampleApplication {
public static function main(): void {
$winterApp = new \dev\winterframework\core\app\WinterWebSwooleApplication();
$winterApp->run(self::class);
}
}

AOP needs no module config. The full sample application.yml sets the server and app identity:

server:
port: 8080
address: 0.0.0.0
context-path: /
winter:
application:
name: AOP Guard Sample Application
id: aop-guard-sample-app
version: 1.0.0

See Configuration for every application.yml key.

Start the application, then call the endpoint with and without the header.

1. Start the application:

Terminal window
composer install
php bin/application.php

2. Call without the header — expect 403:

Terminal window
curl -i http://127.0.0.1:8080/aop-demo/secure-greeting
HTTP/1.1 403 Forbidden
{"success": false, "data": null, "error": "Forbidden"}

The interceptor stopped execution, so the endpoint body never ran.

3. Call with a wrong value — expect 403:

Terminal window
curl -i -H "X-Custom-Foo-Bar: wrong" http://127.0.0.1:8080/aop-demo/secure-greeting

4. Call with the right value — expect 200:

Terminal window
curl -i -H "X-Custom-Foo-Bar: foo-bar" http://127.0.0.1:8080/aop-demo/secure-greeting
HTTP/1.1 200 OK
{"success": true, "data": "Hello from the AOP-guarded endpoint!"}
  • Read AOP for the advice lifecycle (begin/commit/failed), stopExecution, and execution variables.
  • Put reusable advice on #[Service] bean methods the same way — the attribute works there unchanged.