关于 php
面向 PHP 开发者的实践指南,介绍 PHP 8.x 语言特性及常用开发模式。内容还涵盖类型安全、错误处理、安全、测试、性能与 Composer 实践。
主要功能
- 01PHP 8.x 语言特性示例
- 02类型安全与返回类型
- 03依赖注入和仓储模式
- 04异常处理与输入安全
- 05PHPUnit 测试实践
- 06性能与 Composer 建议
适用场景
- 01采用 PHP 8.x 语法编写代码
- 02设计可测试的面向对象结构
- 03验证输入并防范 SQL 注入
- 04为 PHP 项目编写测试与配置依赖
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ vapvarun/ claude-backup --skill php安装后在 Claude Code 中输入/php确认已加载。
详细介绍
PHP 开发
现代 PHP 8.x 开发模式与最佳实践。
PHP 8.x 特性
构造函数属性提升
// 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
) {}
}
命名参数
function createUser(string $name, string $email, bool $admin = false): User {
// ...
}
// Named arguments (order doesn't matter)
createUser(email: '[email protected]', name: 'John', admin: true);
Match 表达式
// 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',
};
空安全运算符
// Before
$country = null;
if ($user !== null && $user->getAddress() !== null) {
$country = $user->getAddress()->getCountry();
}
// PHP 8+
$country = $user?->getAddress()?->getCountry();
联合类型与交叉类型
// 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) {
// ...
}
}
枚举(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"
只读属性(PHP 8.1+)
class User {
public function __construct(
public readonly int $id,
public readonly string $email,
private string $password
) {}
}
$user = new User(1, '[email protected]', 'hashed');
$user->id = 2; // Error: Cannot modify readonly property
类型安全
严格类型
<?php
declare(strict_types=1);
function add(int $a, int $b): int {
return $a + $b;
}
add(1, 2); // OK
add('1', '2'); // TypeError
返回类型
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();
}
}
面向对象编程模式
依赖注入
// 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]);
}
}
值对象
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('[email protected]');
echo $email->toString(); // "[email protected]"
仓储模式
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']
);
}
}
错误处理
自定义异常
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 最佳实践
// 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);
}
安全
输入验证
// 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');
}
密码哈希
// 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 注入
// 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']);
测试
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, '[email protected]');
$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);
}
}
数据提供器
#[DataProvider('validEmailProvider')]
public function testValidEmails(string $email): void {
$result = Email::fromString($email);
$this->assertInstanceOf(Email::class, $result);
}
public static function validEmailProvider(): array {
return [
'simple' => ['[email protected]'],
'with subdomain' => ['[email protected]'],
'with plus' => ['[email protected]'],
];
}
性能
Opcache
; php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0 ; Production only
数组函数
// 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 最佳实践
{
"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
评论
支持 Markdown