📦 deps(thirdparty): update snapshots
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
---
|
||||
name: php
|
||||
description: "Language-specific super-code guidelines for php."
|
||||
risk: safe
|
||||
source: community
|
||||
date_added: "2026-06-16"
|
||||
---
|
||||
# PHP: Idiomatic Efficiency Reference
|
||||
|
||||
## Table of Contents
|
||||
1. [Arrays & Collections](#arrays)
|
||||
2. [Type Safety](#types)
|
||||
3. [Error Handling](#errors)
|
||||
4. [String Handling](#strings)
|
||||
5. [OOP & Modern PHP](#oop)
|
||||
6. [Functions & Closures](#functions)
|
||||
7. [Anti-patterns specific to PHP](#antipatterns)
|
||||
|
||||
---
|
||||
|
||||
## 1. Arrays & Collections {#arrays}
|
||||
|
||||
```php
|
||||
// ❌ Manual accumulation
|
||||
$result = [];
|
||||
foreach ($items as $item) {
|
||||
if ($item->isActive()) {
|
||||
$result[] = strtoupper($item->getName());
|
||||
}
|
||||
}
|
||||
|
||||
// ✅
|
||||
$result = array_map(
|
||||
fn($i) => strtoupper($i->getName()),
|
||||
array_filter($items, fn($i) => $i->isActive())
|
||||
);
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ Manual key-value grouping
|
||||
$grouped = [];
|
||||
foreach ($items as $item) {
|
||||
$grouped[$item->getCategory()][] = $item;
|
||||
}
|
||||
|
||||
// ✅ (PHP 8.1+) — or use the loop above; PHP lacks a built-in groupBy
|
||||
// The foreach is actually idiomatic PHP for grouping. No need to force array_* here.
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ Checking isset then accessing
|
||||
if (isset($data['key'])) {
|
||||
$value = $data['key'];
|
||||
} else {
|
||||
$value = 'default';
|
||||
}
|
||||
|
||||
// ✅
|
||||
$value = $data['key'] ?? 'default';
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ array_push for single element
|
||||
array_push($items, $newItem);
|
||||
|
||||
// ✅
|
||||
$items[] = $newItem;
|
||||
```
|
||||
|
||||
**Use `array_map`/`array_filter` for transforms. The `foreach` loop is fine when array functions would be less readable.**
|
||||
|
||||
---
|
||||
|
||||
## 2. Type Safety {#types}
|
||||
|
||||
```php
|
||||
// ❌ No type declarations
|
||||
function process($items) {
|
||||
return $items;
|
||||
}
|
||||
|
||||
// ✅ (PHP 8.0+)
|
||||
function process(array $items): array {
|
||||
return $items;
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ Union type for nullable
|
||||
function find(string $key): string|null { ... }
|
||||
|
||||
// ✅
|
||||
function find(string $key): ?string { ... }
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ Loose comparison
|
||||
if ($value == '0') { ... } // true for 0, '', false, null
|
||||
|
||||
// ✅
|
||||
if ($value === '0') { ... }
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ Type checking with gettype()
|
||||
if (gettype($x) === 'integer') { ... }
|
||||
|
||||
// ✅
|
||||
if (is_int($x)) { ... }
|
||||
// or with union types, avoid checks entirely
|
||||
```
|
||||
|
||||
**Enable `declare(strict_types=1)` at the top of every file.**
|
||||
|
||||
---
|
||||
|
||||
## 3. Error Handling {#errors}
|
||||
|
||||
```php
|
||||
// ❌ Suppressing errors with @
|
||||
$data = @file_get_contents($path);
|
||||
|
||||
// ✅
|
||||
$data = file_get_contents($path);
|
||||
if ($data === false) {
|
||||
throw new RuntimeException("Failed to read: $path");
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ Catching \Exception and swallowing
|
||||
try { process(); }
|
||||
catch (\Exception $e) { /* silence */ }
|
||||
|
||||
// ✅
|
||||
try {
|
||||
process();
|
||||
} catch (SpecificException $e) {
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
throw new AppException('Processing failed', previous: $e);
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ Returning mixed types for error indication
|
||||
function divide(int $a, int $b): int|false {
|
||||
if ($b === 0) return false;
|
||||
return intdiv($a, $b);
|
||||
}
|
||||
|
||||
// ✅ — throw exception for exceptional cases
|
||||
function divide(int $a, int $b): int {
|
||||
if ($b === 0) throw new \DivisionByZeroError();
|
||||
return intdiv($a, $b);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. String Handling {#strings}
|
||||
|
||||
```php
|
||||
// ❌ Concatenation for variable interpolation
|
||||
$msg = 'Hello, ' . $name . '! You have ' . $count . ' messages.';
|
||||
|
||||
// ✅
|
||||
$msg = "Hello, {$name}! You have {$count} messages.";
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ Manual string contains check
|
||||
if (strpos($haystack, $needle) !== false) { ... }
|
||||
|
||||
// ✅ (PHP 8.0+)
|
||||
if (str_contains($haystack, $needle)) { ... }
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ substr for prefix/suffix check
|
||||
if (substr($str, 0, 4) === 'http') { ... }
|
||||
if (substr($str, -4) === '.php') { ... }
|
||||
|
||||
// ✅ (PHP 8.0+)
|
||||
if (str_starts_with($str, 'http')) { ... }
|
||||
if (str_ends_with($str, '.php')) { ... }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. OOP & Modern PHP {#oop}
|
||||
|
||||
```php
|
||||
// ❌ Manual constructor property assignment
|
||||
class User {
|
||||
private string $name;
|
||||
private int $age;
|
||||
public function __construct(string $name, int $age) {
|
||||
$this->name = $name;
|
||||
$this->age = $age;
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ (PHP 8.0+)
|
||||
class User {
|
||||
public function __construct(
|
||||
private readonly string $name,
|
||||
private readonly int $age,
|
||||
) {}
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ Constants as class properties
|
||||
class Status {
|
||||
const ACTIVE = 'active';
|
||||
const INACTIVE = 'inactive';
|
||||
}
|
||||
|
||||
// ✅ (PHP 8.1+)
|
||||
enum Status: string {
|
||||
case Active = 'active';
|
||||
case Inactive = 'inactive';
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ instanceof chains
|
||||
if ($shape instanceof Circle) { ... }
|
||||
elseif ($shape instanceof Rectangle) { ... }
|
||||
|
||||
// ✅ (PHP 8.0+)
|
||||
$area = match(true) {
|
||||
$shape instanceof Circle => $shape->radius ** 2 * M_PI,
|
||||
$shape instanceof Rectangle => $shape->width * $shape->height,
|
||||
default => throw new \InvalidArgumentException("Unknown shape"),
|
||||
};
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ Named constructor via static method returning new self()
|
||||
class Money {
|
||||
public static function fromCents(int $cents): self {
|
||||
$m = new self();
|
||||
$m->cents = $cents;
|
||||
return $m;
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ (PHP 8.0+) — constructor promotion + named arguments
|
||||
class Money {
|
||||
public function __construct(
|
||||
public readonly int $cents,
|
||||
) {}
|
||||
}
|
||||
$m = new Money(cents: 500);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Functions & Closures {#functions}
|
||||
|
||||
```php
|
||||
// ❌ Verbose closure for simple operation
|
||||
$doubled = array_map(function ($x) { return $x * 2; }, $numbers);
|
||||
|
||||
// ✅ (PHP 7.4+)
|
||||
$doubled = array_map(fn($x) => $x * 2, $numbers);
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ Passing globals or using `global` keyword
|
||||
global $db;
|
||||
function getUser(int $id) {
|
||||
global $db;
|
||||
return $db->find($id);
|
||||
}
|
||||
|
||||
// ✅ — dependency injection
|
||||
function getUser(int $id, PDO $db): ?User {
|
||||
return $db->find($id);
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// ❌ Named arguments abused for every call
|
||||
str_pad(string: $s, length: 10, pad_string: ' ', pad_type: STR_PAD_LEFT);
|
||||
|
||||
// ✅ — named args are useful for readability on ambiguous params; don't force
|
||||
str_pad($s, 10, ' ', STR_PAD_LEFT);
|
||||
// but named args shine for: new User(name: 'Alice', age: 30)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Anti-patterns specific to PHP {#antipatterns}
|
||||
|
||||
| Anti-pattern | Preferred |
|
||||
|---|---|
|
||||
| `==` for comparison | `===` (strict equality) |
|
||||
| `@` error suppression | explicit error handling |
|
||||
| `global` keyword | dependency injection |
|
||||
| `extract()` on user input | access keys explicitly |
|
||||
| `die()` / `exit()` in library code | throw exception |
|
||||
| `strpos !== false` for contains | `str_contains()` (PHP 8.0) |
|
||||
| Manual constructor assignment | constructor promotion (PHP 8.0) |
|
||||
| Class constants for enums | `enum` (PHP 8.1) |
|
||||
| `mixed` return types | specific typed returns |
|
||||
| `array` for everything | typed classes / DTOs |
|
||||
| `var_dump` / `print_r` debugging | proper logging (PSR-3) |
|
||||
| Not using `declare(strict_types=1)` | always enable |
|
||||
|
||||
|
||||
|
||||
## Limitations
|
||||
- These are language-specific guidelines and do not cover overall architectural decisions.
|
||||
- Over-compression might reduce readability; apply judgement.
|
||||
Reference in New Issue
Block a user