--- id: miles990/claude-software-skills/php version: "43b47ed3" license: MIT install: manual updated: 2026-01-20 --- # php — This skill covers contemporary PHP development with PHP 7.4+ and 8.x features, including strict typing, constructor promotion, union and intersection types, and attributes. It explores object-oriented patterns through traits, interfaces, and abstract classes, plus enums and custom exception handling. Publisher: miles990 · Stars: 19 · Updated: 2026-01-20 Install (manual): `git clone https://github.com/miles990/claude-software-skills` ## SKILL.md # PHP ## Overview Modern PHP (7.4+/8.x) patterns including typed properties, attributes, and modern OOP features. --- ## Modern PHP Features ### Type System ```php id = uniqid(); $this->createdAt = new DateTimeImmutable(); } } // Union types (PHP 8.0+) function process(string|int $value): string|int { return is_string($value) ? strtoupper($value) : $value * 2; } // Intersection types (PHP 8.1+) function processIterable(Countable&Iterator $items): int { return count($items); } // Return types function findUser(string $id): ?User { return $this->repository->find($id); } function getUsers(): array { return $this->repository->findAll(); } // Never return type (PHP 8.1+) function fail(string $message): never { throw new RuntimeException($message); } // Nullable types function setName(?string $name): void { $this->name = $name; } ``` ### Attributes (PHP 8.0+) ```php userService->getAll(); } #[Route(path: '/users/{id}', method: 'GET')] public function show(string $id): User { return $this->userService->find($id); } } // Reading attributes $reflection = new ReflectionClass(User::class); $attributes = $reflection->getAttributes(Entity::class); foreach ($attributes as $attribute) { $instance = $attribute->newInstance(); echo $instance->table; // 'users' } ``` ### Enums (PHP 8.1+) ```php 'Pending Review', self::Active => 'Active', self::Inactive => 'Inactive', }; } } // Backed enum (with values) enum Role: string { case Admin = 'admin'; case Moderator = 'moderator'; case User = 'user'; public function permissions(): array { return match ($this) { self::Admin => ['read', 'write', 'delete', 'admin'], self::Moderator => ['read', 'write', 'delete'], self::User => ['read', 'write'], }; } public static function fromString(string $value): self { return self::from($value); } public static function tryFromString(string $value): ?self { return self::tryFrom($value); } } // Usage $status = Status::Active; echo $status->label(); // "Active" $role = Role::Admin; echo $role->value; // "admin" $userRole = Role::from('user'); $permissions = $userRole->permissions(); ``` --- ## Object-Oriented Patterns ### Traits ```php createdAt; } public function getUpdatedAt(): ?DateTimeImmutable { return $this->updatedAt; } public function touch(): void { $now = new DateTimeImmutable(); $this->createdAt ??= $now; $this->updatedAt = $now; } } trait SoftDeletable { protected ?DateTimeImmutable $deletedAt = null; public function delete(): void { $this->deletedAt = new DateTimeImmutable(); } public function restore(): void { $this->deletedAt = null; } public function isDeleted(): bool { return $this->deletedAt !== null; } } // Using traits class Document { use Timestampable; use SoftDeletable; public function __construct( public string $title, public string $content ) { $this->touch(); } } // Trait conflict resolution trait A { public function hello(): string { return 'Hello from A'; } } trait B { public function hello(): string { return 'Hello from B'; } } class MyClass { use A, B { A::hello insteadof B; B::hello as helloFromB; } } ``` ### Interfaces and Abstract Classes ```php pdo->prepare( "SELECT * FROM {$this->table} WHERE id = :id" ); $stmt->execute(['id' => $id]); $row = $stmt->fetch(PDO::FETCH_ASSOC); return $row ? $this->hydrate($row) : null; } public function findAll(): array { $stmt = $this->pdo->query("SELECT * FROM {$this->table}"); return array_map( fn(array $row) => $this->hydrate($row), $stmt->fetchAll(PDO::FETCH_ASSOC) ); } } // Concrete implementation class UserRepository extends BaseRepository { public function __construct(PDO $pdo) { parent::__construct($pdo, 'users'); } protected function hydrate(array $row): User { return new User( id: $row['id'], email: $row['email'], name: $row['name'] ); } public function findByEmail(string $email): ?User { // Custom method } } ``` --- ## Error Handling ```php $errors], $previous ); } } class NotFoundException extends AppException { public function __construct( string $resource, string $id, ?Throwable $previous = null ) { parent::__construct( "{$resource} not found: {$id}", 'NOT_FOUND', ['resource' => $resource, 'id' => $id], $previous ); } } // Result pattern readonly class Result { private function __construct( public mixed $value, public ?string $error, public bool $success ) {} public static function success(mixed $value): self { return new self($value, null, true); } public static function failure(string $error): self { return new self(null, $error, false); } public function map(callable $fn): self { if (!$this->success) { return $this; } return self::success($fn($this->value)); } public function flatMap(callable $fn): self { if (!$this->success) { return $this; } return $fn($this->value); } } // Usage function createUser(array $data): Result { if (empty($data['email'])) { return Result::failure('Email is required'); } try { $user = new User($data['email'], $data['name'] ?? ''); $this->repository->save($user); return Result::success($user); } catch (Exception $e) { return Result::failure($e->getMessage()); } } ``` --- ## Collections and Arrays ```php 'Alice', 'age' => 30], ['name' => 'Bob', 'age' => 25], ['name' => 'Charlie', 'age' => 35], ]; // Filter $adults = array_filter($users, fn($u) => $u['age'] >= 30); // Map $names = array_map(fn($u) => $u['name'], $users); // Reduce $totalAge = array_reduce($users, fn($sum, $u) => $sum + $u['age'], 0); // Find $bob = array_filter($users, fn($u) => $u['name'] === 'Bob'); $bob = current($bob); // Get first match // Sort usort($users, fn($a, $b) => $a['age'] <=> $b['age']); // Group by (custom) function groupBy(array $items, string $key): array { return array_reduce($items, function ($groups, $item) use ($key) { $groups[$item[$key]][] = $item; return $groups; }, []); } // Collection class class Collection implements Countable, IteratorAggregate { public function __construct(private array $items = []) {} public static function from(array $items): self { return new self($items); } public function map(callable $fn): self { return new self(array_map($fn, $this->items)); } public function filter(callable $fn): self { return new self(array_filter($this->items, $fn)); } public function reduce(callable $fn, mixed $initial = null): mixed { return array_reduce($this->items, $fn, $initial); } public function first(): mixed { return $this->items[array_key_first($this->items)] ?? null; } public function count(): int { return count($this->items); } public function getIterator(): Traversable { return new ArrayIterator($this->items); } public function toArray(): array { return $this->items; } } // Usage $result = Collection::from($users) ->filter(fn($u) => $u['age'] >= 30) ->map(fn($u) => $u['name']) ->toArray(); ``` --- ## Dependency Injection ```php logger->info('Creating user', ['email' => $email]); $user = new User($email, $name); $this->repository->save($user); $this->events->dispatch(new UserCreated($user)); return $user; } } // Simple container class Container { private array $bindings = []; private array $instances = []; public function bind(string $abstract, callable $concrete): void { $this->bindings[$abstract] = $concrete; } public function singleton(string $abstract, callable $concrete): void { $this->bindings[$abstract] = function ($c) use ($abstract, $concrete) { if (!isset($this->instances[$abstract])) { $this->instances[$abstract] = $concrete($c); } return $this->instances[$abstract]; }; } public function get(string $abstract): mixed { if (isset($this->bindings[$abstract])) { return $this->bindings[$abstract]($this); } return $this->resolve($abstract); } private function resolve(string $class): object { $reflection = new ReflectionClass($class); $constructor = $reflection->getConstructor(); if (!$constructor) { return new $class(); } $params = array_map( fn(ReflectionParameter $p) => $this->get($p->getType()->getName()), $constructor->getParameters() ); return $reflection->newInstanceArgs($params); } } ``` --- ## Related Skills - [[backend]] - Laravel, Symfony - [[database]] - Doctrine, Eloquent - [[testing]] - PHPUnit, Pest [View on SkillFed](https://skillfed.io/miles990/claude-software-skills/php) · [View on GitHub](https://github.com/miles990/claude-software-skills)