До PHP 5.3 весь код жил в глобальном пространстве имён — функции, классы, константы. Два библиотечных класса с именем Logger — и сайт падает с Fatal error.
Неймспейсы и трейты — не «синтаксический сахар». Это реакция на рост проектов и необходимость композиции.
Проблема: конфликты имён в крупных проектах.
Решение: «венгерская нотация» и префиксы:
// Библиотека A
class MyLib_Logger { ... }
function MyLib_log($msg) { ... }
// Библиотека B
class Other_Logger { ... } // пришлось переименовать вручную
→ Тяжело поддерживать, не масштабируется.
Что изменилось:
namespace, use, __NAMESPACE__.
// Файл: src/Logger/FileLogger.php
class MyProject_Logger_FileLogger { ... }
После:
// Файл: src/Logger/FileLogger.php
namespace MyProject\Logger;
class FileLogger { ... } // имя короче, логичнее
Импорт:
use MyProject\Logger\FileLogger;
use MyProject\DB as Database; // алиас
$logger = new FileLogger();
$db = new Database\Connection();
Важно: неймспейсы — компиляционная фича. В рантайме имя класса = MyProject\Logger\FileLogger (строка).
static:: вместо self::До PHP 5.3: self:: ссылался на класс, где метод определён, а не где вызван.
Было (проблема наследования):
class A {
public static function who() { echo __CLASS__; }
public static function test() { self::who(); } // ← всегда A
}
class B extends A {
public static function who() { echo __CLASS__; }
}
B::test(); // → выводит "A", а ожидалось "B"
Стало (PHP 5.3+):
class A {
public static function who() { echo __CLASS__; }
public static function test() { static::who(); } // ← late static binding
}
class B extends A {
public static function who() { echo __CLASS__; }
}
B::test(); // → "B" ✅
💡 static:: — не «магия», а ссылка на класс, из которого вызван метод (runtime), а не где он объявлен (compile time).
До PHP 5.3 — только именованные функции и create_function() (небезопасно, медленно).
PHP 5.3+: анонимные функции с use
$multiplier = 3;
$double = function($n) use ($multiplier) {
return $n * $multiplier;
};
echo $double(5); // 15
→ use захватывает переменные по значению. Для захвата по ссылке — use (&$var).
$users = [
['name' => 'Иван', 'age' => 28],
['name' => 'Анна', 'age' => 24]
];
// Сортировка по возрасту
usort($users, function($a, $b) {
return $a['age'] <=> $b['age'];
});
⚠️ Ловушка: внутри замыкания$thisнедоступен (добавили только в PHP 5.4 через$func = function() { ... }; $func = $func->bindTo($this);).
Проблема: множественное наследование запрещено, но код дублируется (например, log(), validate() в разных классах).
Решение до трейтов:
__call(),После трейтов:
trait Loggable {
protected function log(string $msg): void {
file_put_contents('app.log', "$msg\n", FILE_APPEND);
}
}
trait Validatable {
protected function validate(array $data): bool {
return !empty($data);
}
}
class User {
use Loggable, Validatable;
public function save(array $data) {
if ($this->validate($data)) {
$this->log('Saving user');
// ...
}
}
}
Было:
$arr = array(1, 2, 3);
$assoc = array('a' => 1, 'b' => 2);
Стало:
$arr = [1, 2, 3];
$assoc = ['a' => 1, 'b' => 2];
То же самое в JSON-подобном синтаксисе. Поддерживается везде: return, foreach, array_merge([...])
Было:
$tmp = explode(',', 'a,b,c');
echo $tmp[1]; // b
Стало:
echo explode(',', 'a,b,c')[1]; // b
Работает также для:
getArray()[0],[1,2,3][1],(new User)->name.⚠️ Не работает для констант массивов (MY_CONST[0]) — добавили только в PHP 5.5.
Запуск:
php -S localhost:8000
— сервер стартует в текущей директории, index.php — точка входа.
Для кастомного роутинга — router.php::
php -S localhost:8000 router.php
📌 Только для локальной разработки. Не использовать в продакшене.
| Фича | Ловушка | Как избежать |
|---|---|---|
namespace |
new Logger() ≠ new \Logger() — ищет в текущем неймспейсе |
Всегда используй use или \ для глобальных классов |
trait |
Коллизия методов: use A, B, если оба имеют log() |
use A, B { A::log insteadof B; B::log as logBackup; } |
| Неймспейсы + автозагрузка | MyProject\Logger → ожидает файл MyProject/Logger.php |
Используй PSR-4: "MyProject\\": "src/" в composer.json |
yield)Зачем: итерация по большим данным без загрузки всего в память.
Пример:
function xrange($start, $end) {
for ($i = $start; $i <= $end; $i++) {
yield $i; // возвращает значение, но сохраняет состояние
}
}
foreach (xrange(1, 1000000) as $n) { /* не жрёт память */ }
finally в try-catchБыло: нет гарантированного выполнения после try/catch.
Стало:
try {
// ...
} catch (Exception $e) {
// ...
} finally {
// Всегда выполнится — даже при return в try/catch
$db->close();
}
🏷️ ::class — магическая константа класса
Было:
$className = 'My\\Namespace\\User'; // строка → ошибка при рефакторинге
Стало:
$className = User::class; // → "My\Namespace\User", проверяется на этапе компиляции
Работает для любого класса, даже если не загружен (не требует use).
Проблема: md5(), sha1() — небезопасны; ручная соль — ошибка.
Решение:
// Хэширование
$hash = password_hash($password, PASSWORD_DEFAULT);
// Проверка
if (password_verify($input, $hash)) { /* OK */ }
// Проверка устаревания (например, сменился алгоритм)
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
$hash = password_hash($password, PASSWORD_DEFAULT);
}
→ Автоматическая соль, адаптивная стоимость, защита от тайминг-атак.