Copy docker run --rm zchencow/innozverse-php:latest php -r '
<?php
// ── Observer / Event System ───────────────────────────────────────────────────
echo "=== Observer (Event System) ===" . PHP_EOL;
interface EventListener {
public function handle(string $event, array $data): void;
}
class EventEmitter {
private array $listeners = [];
public function on(string $event, EventListener|callable $listener): void {
$this->listeners[$event][] = $listener;
}
public function emit(string $event, array $data = []): void {
foreach ($this->listeners[$event] ?? [] as $listener) {
is_callable($listener) ? $listener($data) : $listener->handle($event, $data);
}
}
}
class EmailNotifier implements EventListener {
public array $sent = [];
public function handle(string $event, array $data): void {
$this->sent[] = "Email: [{$event}] Order #{$data["orderId"]} - {$data["product"]}";
}
}
class InventoryManager implements EventListener {
public array $changes = [];
public function handle(string $event, array $data): void {
if ($event === "order.placed") {
$this->changes[] = "Deduct stock: {$data["product"]} × {$data["qty"]}";
}
}
}
$events = new EventEmitter();
$email = new EmailNotifier();
$inventory = new InventoryManager();
$events->on("order.placed", $email);
$events->on("order.placed", $inventory);
$events->on("order.shipped", $email);
$events->on("order.cancelled", $email);
$events->on("order.cancelled", fn($d) => print(" ⚡ Webhook: refund for #{$d["orderId"]}" . PHP_EOL));
$events->emit("order.placed", ["orderId" => 1001, "product" => "Surface Pro", "qty" => 2]);
$events->emit("order.shipped", ["orderId" => 1001, "product" => "Surface Pro", "qty" => 2]);
$events->emit("order.cancelled", ["orderId" => 1002, "product" => "USB-C Hub", "qty" => 1]);
foreach ($email->sent as $e) echo " " . $e . PHP_EOL;
foreach ($inventory->changes as $c) echo " " . $c . PHP_EOL;
// ── Strategy ─────────────────────────────────────────────────────────────────
echo PHP_EOL . "=== Strategy ===" . PHP_EOL;
interface SortStrategy {
public function sort(array &$items): void;
public function name(): string;
}
class PriceAscStrategy implements SortStrategy {
public function sort(array &$items): void { usort($items, fn($a,$b) => $a["price"] <=> $b["price"]); }
public function name(): string { return "Price ↑"; }
}
class NameStrategy implements SortStrategy {
public function sort(array &$items): void { usort($items, fn($a,$b) => strcmp($a["name"], $b["name"])); }
public function name(): string { return "Name A→Z"; }
}
class ValueStrategy implements SortStrategy {
public function sort(array &$items): void {
usort($items, fn($a,$b) => ($b["price"]*$b["stock"]) <=> ($a["price"]*$a["stock"]));
}
public function name(): string { return "Value ↓"; }
}
class ProductCatalogue {
private SortStrategy $strategy;
public function __construct(SortStrategy $strategy) { $this->strategy = $strategy; }
public function setStrategy(SortStrategy $s): void { $this->strategy = $s; }
public function sort(array $items): array {
$this->strategy->sort($items);
return $items;
}
}
$products = [
["name" => "Surface Pro", "price" => 864.00, "stock" => 15],
["name" => "Surface Pen", "price" => 49.99, "stock" => 80],
["name" => "Office 365", "price" => 99.99, "stock" => 999],
["name" => "USB-C Hub", "price" => 29.99, "stock" => 0],
];
$cat = new ProductCatalogue(new PriceAscStrategy());
foreach ([new PriceAscStrategy(), new NameStrategy(), new ValueStrategy()] as $strategy) {
$cat->setStrategy($strategy);
$sorted = $cat->sort($products);
echo " " . $strategy->name() . ": " . implode(", ", array_column($sorted, "name")) . PHP_EOL;
}
// ── Decorator ─────────────────────────────────────────────────────────────────
echo PHP_EOL . "=== Decorator ===" . PHP_EOL;
interface Logger {
public function log(string $message): void;
public function getLogs(): array;
}
class ConsoleLogger implements Logger {
private array $logs = [];
public function log(string $message): void {
$this->logs[] = $message;
echo " [CONSOLE] " . $message . PHP_EOL;
}
public function getLogs(): array { return $this->logs; }
}
// Decorator: adds timestamp without modifying ConsoleLogger
class TimestampLogger implements Logger {
public function __construct(private Logger $inner) {}
public function log(string $message): void {
$this->inner->log("[" . date("H:i:s") . "] " . $message);
}
public function getLogs(): array { return $this->inner->getLogs(); }
}
// Decorator: adds severity prefix
class LevelLogger implements Logger {
public function __construct(private Logger $inner, private string $level = "INFO") {}
public function log(string $message): void {
$this->inner->log("[{$this->level}] " . $message);
}
public function getLogs(): array { return $this->inner->getLogs(); }
}
// Stack decorators — each wraps the previous
$logger = new LevelLogger(new TimestampLogger(new ConsoleLogger()), "INFO");
$logger->log("Order #1001 placed: Surface Pro ×2 = \$1728.00");
$logger->log("Payment processed via Stripe");
echo " Total log entries: " . count($logger->getLogs()) . PHP_EOL;
'