Claude
Skills
Sign in
Back

developing-with-php

Included with Lifetime
$97 forever

Modern PHP 8.x development with type system, attributes, enums, error handling, and Composer. Use when writing PHP code or working with PHP projects.

Writing & Docs

What this skill does


# PHP Skill - Quick Reference

Core PHP language patterns for modern development. For Laravel-specific patterns, see the Laravel skill.

> **Progressive Disclosure**: This is the quick reference. See [REFERENCE.md](./REFERENCE.md) for comprehensive patterns, advanced examples, and deep-dives.

## Table of Contents

1. [PHP 8.x Type System](#php-8x-type-system)
2. [Constructor Property Promotion](#constructor-property-promotion)
3. [Enums](#enums)
4. [Match Expression & Named Arguments](#match-expression--named-arguments)
5. [Attributes](#attributes)
6. [Null Safety](#null-safety)
7. [OOP Essentials](#oop-essentials)
8. [Handler/Service Pattern](#handlerservice-pattern)
9. [Map/DTO Pattern](#mapdto-pattern)
10. [PDO Database Access](#pdo-database-access)
11. [Composer & Autoloading](#composer--autoloading)
12. [Error Handling](#error-handling)
13. [Testing with PHPUnit](#testing-with-phpunit)
14. [Array Operations Quick Reference](#array-operations-quick-reference)
15. [Security Essentials](#security-essentials)
16. [Quick Reference Tables](#quick-reference-tables)
17. [Related Resources](#related-resources)

---

## PHP 8.x Type System

```php
<?php
// Union types (8.0+)
function process(string|int $value): string|false { }

// Intersection types (8.1+)
function handle(Countable&Iterator $collection): void { }

// Nullable types
function find(int $id): ?User { }

// Never return type (8.1+)
function fail(): never {
    throw new Exception('Fatal error');
}

// True, false, null as standalone types (8.2+)
function isValid(): true { return true; }
```

## Constructor Property Promotion

```php
<?php
// Promoted properties (8.0+) - replaces boilerplate
class User {
    public function __construct(
        private string $name,
        private string $email,
        private bool $active = true,
    ) {}
}

// Readonly class (8.2+) - all properties are readonly
readonly class ValueObject {
    public function __construct(
        public string $value,
        public DateTimeImmutable $createdAt,
    ) {}
}
```

## Enums

```php
<?php
// Backed enum with values (8.1+)
enum Status: string {
    case Draft = 'draft';
    case Published = 'published';
    case Archived = 'archived';

    public function label(): string {
        return match($this) {
            self::Draft => 'Draft',
            self::Published => 'Published',
            self::Archived => 'Archived',
        };
    }
}

// Usage
$status = Status::Published;
$value = $status->value;                 // 'published'
$all = Status::cases();                  // Array of all cases
$fromValue = Status::from('draft');      // Status::Draft
$tryFrom = Status::tryFrom('invalid');   // null (no exception)
```

> See [REFERENCE.md](./REFERENCE.md#enum-patterns) for EnumTrait pattern and advanced enum usage.

## Match Expression & Named Arguments

```php
<?php
// Match returns value, uses strict comparison
$result = match($status) {
    Status::Draft => 'Not ready',
    Status::Published => 'Live',
    Status::Archived => 'Hidden',
};

// Multiple conditions
$category = match($code) {
    200, 201, 204 => 'success',
    400, 422 => 'client_error',
    500, 502, 503 => 'server_error',
    default => 'unknown',
};

// Named arguments (skip defaults, any order)
$user = createUser(
    email: '[email protected]',
    name: 'John Doe',
    role: 'admin',
);
```

## Attributes

```php
<?php
#[Attribute]
class Route {
    public function __construct(
        public string $path,
        public string $method = 'GET',
    ) {}
}

class UserController {
    #[Route('/users', 'GET')]
    public function index(): array { }
}

// Reading attributes via reflection
$reflection = new ReflectionMethod(UserController::class, 'index');
$attributes = $reflection->getAttributes(Route::class);
$route = $attributes[0]->newInstance();
echo $route->path;  // '/users'
```

## Null Safety

```php
<?php
// Null coalescing
$name = $user->name ?? 'Anonymous';

// Null coalescing assignment
$data['count'] ??= 0;

// Nullsafe operator (8.0+)
$country = $user?->address?->country?->name;

// Combined
$timezone = $user?->settings?->timezone ?? 'UTC';
```

---

## OOP Essentials

### Interfaces & Abstract Classes

```php
<?php
interface RepositoryInterface {
    public function find(int $id): ?object;
    public function save(object $entity): void;
}

abstract class BaseHandler {
    public function __construct(protected PDO $db) {}
    abstract public function handle(array $data): mixed;
}
```

### Traits

```php
<?php
trait Timestamps {
    protected ?DateTimeImmutable $createdAt = null;

    public function setCreatedAt(): void {
        $this->createdAt = new DateTimeImmutable();
    }
}

class User {
    use Timestamps;
}
```

> See [REFERENCE.md](./REFERENCE.md#oop-patterns) for trait conflict resolution, late static binding, and magic methods.

---

## Handler/Service Pattern

```php
<?php
class UserHandler {
    public function __construct(
        private readonly PDO $db,
        private readonly CacheInterface $cache,
    ) {}

    public function get(int $id): ?array {
        $cacheKey = "user:{$id}";
        if ($cached = $this->cache->get($cacheKey)) {
            return $cached;
        }

        $stmt = $this->db->prepare('SELECT * FROM users WHERE id = ?');
        $stmt->execute([$id]);
        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        if ($user) {
            $this->cache->set($cacheKey, $user, 3600);
        }
        return $user ?: null;
    }
}
```

> See [REFERENCE.md](./REFERENCE.md#handler-patterns) for CRUD handlers, aggregation patterns, and collection mapping.

---

## Map/DTO Pattern

```php
<?php
readonly class UserMap {
    public function __construct(
        public int $id,
        public string $name,
        public string $email,
    ) {}

    public static function fromRow(array $row): self {
        return new self(
            id: (int) $row['id'],
            name: trim($row['first_name'] . ' ' . $row['last_name']),
            email: $row['email'],
        );
    }

    public function toArray(): array {
        return ['id' => $this->id, 'name' => $this->name, 'email' => $this->email];
    }
}
```

> See [REFERENCE.md](./REFERENCE.md#dto-patterns) for nested mapping and collection patterns.

---

## PDO Database Access

### Connection

```php
<?php
$dsn = 'mysql:host=localhost;dbname=myapp;charset=utf8mb4';
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, 'username', 'password', $options);
```

### Prepared Statements

```php
<?php
// Named parameters
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $email]);
$user = $stmt->fetch();

// Positional parameters
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
```

### Transactions

```php
<?php
try {
    $pdo->beginTransaction();
    // Multiple operations...
    $pdo->commit();
} catch (Exception $e) {
    $pdo->rollBack();
    throw $e;
}
```

> See [REFERENCE.md](./REFERENCE.md#pdo-advanced) for stored procedures, batch operations, and SQL file execution.

---

## Composer & Autoloading

### composer.json Essentials

```json
{
    "require": {
        "php": "^8.2"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    }
}
```

### Version Constraints

| Constraint | Meaning |
|------------|---------|
| `^1.0` | `>=1.0.0 <2.0.0` |
| `~1.2` | `>=1.2.0 <1.3.0` |
| `1.0.*` | `>=1.0.0 <1.1.0` |

---

## Error Handling

### Exception Pattern

```php
<?php
class AppException extends Exception {
    public function __construct(
        string $message,
        int $code = 0,
        public readonly array $context = [],
    ) {
        parent::__construct($message, $code);
    }
}

class NotFoundException extends AppEx

Related in Writing & Docs