php

📁 vapvarun/claude-backup 📅 Jan 20, 2026
47
总安装量
47
周安装量
#4482
全站排名
安装命令
npx skills add https://github.com/vapvarun/claude-backup --skill php

Agent 安装分布

claude-code 29
gemini-cli 28
antigravity 26
opencode 23
codex 22
windsurf 20

Skill 文档

PHP Development

Modern PHP 8.x development patterns and best practices.

PHP 8.x Features

Constructor Property Promotion

// Before PHP 8
class User {
    private string $name;
    private int $age;

    public function __construct(string $name, int $age) {
        $this->name = $name;
        $this->age = $age;
    }
}

// PHP 8+
class User {
    public function __construct(
        private string $name,
        private int $age,
        private bool $active = true
    ) {}
}

Named Arguments

function createUser(string $name, string $email, bool $admin = false): User {
    // ...
}

// Named arguments (order doesn't matter)
createUser(email: 'john@example.com', name: 'John', admin: true);

Match Expression

// BAD: Switch with many breaks
switch ($status) {
    case 'pending':
        $color = 'yellow';
        break;
    case 'approved':
        $color = 'green';
        break;
    default:
        $color = 'gray';
}

// GOOD: Match expression
$color = match($status) {
    'pending' => 'yellow',
    'approved', 'published' => 'green',
    'rejected' => 'red',
    default => 'gray',
};

Null Safe Operator

// Before
$country = null;
if ($user !== null && $user->getAddress() !== null) {
    $country = $user->getAddress()->getCountry();
}

// PHP 8+
$country = $user?->getAddress()?->getCountry();

Union Types & Intersection Types

// Union types
function process(int|float|string $value): int|float {
    return is_string($value) ? strlen($value) : $value * 2;
}

// Intersection types (PHP 8.1+)
function save(Countable&Iterator $items): void {
    foreach ($items as $item) {
        // ...
    }
}

Enums (PHP 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',
        };
    }

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

// Usage
$post->status = Status::Published;
echo $post->status->label(); // "Published"

Readonly Properties (PHP 8.1+)

class User {
    public function __construct(
        public readonly int $id,
        public readonly string $email,
        private string $password
    ) {}
}

$user = new User(1, 'john@example.com', 'hashed');
$user->id = 2; // Error: Cannot modify readonly property

Type Safety

Strict Types

<?php
declare(strict_types=1);

function add(int $a, int $b): int {
    return $a + $b;
}

add(1, 2);     // OK
add('1', '2'); // TypeError

Return Types

class UserRepository {
    public function find(int $id): ?User {
        // Returns User or null
    }

    public function findOrFail(int $id): User {
        return $this->find($id) ?? throw new NotFoundException();
    }

    public function all(): array {
        // Returns array of Users
    }

    public function save(User $user): void {
        // Returns nothing
    }

    public function delete(User $user): never {
        // Never returns (throws or exits)
        throw new NotImplementedException();
    }
}

OOP Patterns

Dependency Injection

// BAD: Hard dependency
class OrderService {
    private $mailer;

    public function __construct() {
        $this->mailer = new SmtpMailer(); // Hard to test
    }
}

// GOOD: Dependency injection
interface MailerInterface {
    public function send(string $to, string $subject, string $body): void;
}

class OrderService {
    public function __construct(
        private MailerInterface $mailer,
        private LoggerInterface $logger
    ) {}

    public function complete(Order $order): void {
        $this->mailer->send($order->email, 'Order Complete', '...');
        $this->logger->info('Order completed', ['id' => $order->id]);
    }
}

Value Objects

final class Email {
    private function __construct(
        private readonly string $value
    ) {}

    public static function fromString(string $email): self {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException('Invalid email');
        }
        return new self(strtolower($email));
    }

    public function toString(): string {
        return $this->value;
    }

    public function equals(self $other): bool {
        return $this->value === $other->value;
    }
}

// Usage
$email = Email::fromString('John@Example.com');
echo $email->toString(); // "john@example.com"

Repository Pattern

interface UserRepositoryInterface {
    public function find(int $id): ?User;
    public function findByEmail(string $email): ?User;
    public function save(User $user): void;
    public function delete(User $user): void;
}

class DatabaseUserRepository implements UserRepositoryInterface {
    public function __construct(
        private PDO $pdo
    ) {}

    public function find(int $id): ?User {
        $stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = ?');
        $stmt->execute([$id]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        return $row ? $this->hydrate($row) : null;
    }

    private function hydrate(array $data): User {
        return new User(
            id: $data['id'],
            email: $data['email'],
            name: $data['name']
        );
    }
}

Error Handling

Custom Exceptions

class DomainException extends Exception {}
class ValidationException extends DomainException {}
class NotFoundException extends DomainException {}

class InsufficientFundsException extends DomainException {
    public function __construct(
        public readonly float $balance,
        public readonly float $required
    ) {
        parent::__construct(
            "Insufficient funds: have {$balance}, need {$required}"
        );
    }
}

// Usage
throw new InsufficientFundsException(balance: 50.00, required: 100.00);

Try-Catch Best Practices

// BAD: Catching generic Exception
try {
    $result = $service->process($data);
} catch (Exception $e) {
    log($e->getMessage());
}

// GOOD: Specific exception handling
try {
    $result = $service->process($data);
} catch (ValidationException $e) {
    return response()->json(['errors' => $e->getErrors()], 422);
} catch (NotFoundException $e) {
    return response()->json(['error' => 'Not found'], 404);
} catch (Throwable $e) {
    $this->logger->error('Unexpected error', ['exception' => $e]);
    return response()->json(['error' => 'Server error'], 500);
}

Security

Input Validation

// Always validate and sanitize input
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$age = filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT, [
    'options' => ['min_range' => 0, 'max_range' => 150]
]);

if ($email === false || $email === null) {
    throw new ValidationException('Invalid email');
}

Password Hashing

// Always use password_hash/password_verify
$hash = password_hash($password, PASSWORD_DEFAULT);

if (password_verify($inputPassword, $storedHash)) {
    // Password correct

    // Rehash if needed (algorithm upgrade)
    if (password_needs_rehash($storedHash, PASSWORD_DEFAULT)) {
        $newHash = password_hash($inputPassword, PASSWORD_DEFAULT);
        $user->updatePassword($newHash);
    }
}

SQL Injection Prevention

// BAD: Direct concatenation
$sql = "SELECT * FROM users WHERE email = '$email'"; // VULNERABLE

// GOOD: Prepared statements
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);

// GOOD: Named parameters
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email AND status = :status');
$stmt->execute(['email' => $email, 'status' => 'active']);

Testing

PHPUnit

class UserServiceTest extends TestCase {
    private UserService $service;
    private MockObject $repository;

    protected function setUp(): void {
        $this->repository = $this->createMock(UserRepositoryInterface::class);
        $this->service = new UserService($this->repository);
    }

    public function testFindUserReturnsUser(): void {
        $expected = new User(1, 'john@example.com');
        $this->repository
            ->expects($this->once())
            ->method('find')
            ->with(1)
            ->willReturn($expected);

        $result = $this->service->find(1);

        $this->assertEquals($expected, $result);
    }

    public function testFindUserThrowsWhenNotFound(): void {
        $this->repository
            ->method('find')
            ->willReturn(null);

        $this->expectException(NotFoundException::class);

        $this->service->findOrFail(999);
    }
}

Data Providers

#[DataProvider('validEmailProvider')]
public function testValidEmails(string $email): void {
    $result = Email::fromString($email);
    $this->assertInstanceOf(Email::class, $result);
}

public static function validEmailProvider(): array {
    return [
        'simple' => ['test@example.com'],
        'with subdomain' => ['test@mail.example.com'],
        'with plus' => ['test+label@example.com'],
    ];
}

Performance

Opcache

; php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0  ; Production only

Array Functions

// Use array functions instead of loops when possible
$names = array_map(fn($user) => $user->name, $users);
$adults = array_filter($users, fn($user) => $user->age >= 18);
$total = array_reduce($orders, fn($sum, $order) => $sum + $order->total, 0);

// Generators for large datasets
function readLargeFile(string $path): Generator {
    $handle = fopen($path, 'r');
    while (($line = fgets($handle)) !== false) {
        yield trim($line);
    }
    fclose($handle);
}

foreach (readLargeFile('huge.csv') as $line) {
    // Process one line at a time, low memory
}

Composer Best Practices

{
    "require": {
        "php": "^8.2",
        "monolog/monolog": "^3.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^10.0",
        "phpstan/phpstan": "^1.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "config": {
        "sort-packages": true,
        "optimize-autoloader": true
    }
}
# Production deployment
composer install --no-dev --optimize-autoloader --classmap-authoritative