Изучаем PHP 5: от базовых классов до продвинутых средств

Раздел: PHP -> Версии PHP

Основные возможности PHP 5

PHP 5 стал важным этапом развития языка, внедрив современную объектно-ориентированную модель, механизм исключений, улучшенную работу с базами данных через PDO и другие новшества. В этой статье рассматриваются ключевые возможности PHP 5 с примерами кода.

Как создать и использовать классы в PHP 5?

Основой ООП в PHP 5 является класс. Класс объявляется с помощью ключевого слова class. Свойства и методы могут иметь модификаторы доступа public, protected и private. Конструктор определяется методом __construct.

<?php
class User {
    public $name;
    private $password;
    
    public function __construct($name, $password) {
        $this->name = $name;
        $this->password = password_hash($password, PASSWORD_DEFAULT);
    }
    
    public function verifyPassword($password) {
        return password_verify($password, $this->password);
    }
}

$user = new User('Иван', 'secret123');
echo $user->name; // Иван
var_dump($user->verifyPassword('wrong')); // false
?>
Иван
bool(false)

Типичные ошибки:

  • Забывание указать модификатор доступа – по умолчанию public.
  • Обращение к приватному свойству извне класса вызывает фатальную ошибку.
  • Использование $this в статическом методе.

Решение: всегда явно объявлять видимость, для статических методов использовать self:: или static::.

Как реализовать наследование и интерфейсы?

Наследование позволяет создавать иерархию классов. Ключевое слово extends. Интерфейсы задают контракты с помощью interface и implements.

<?php
interface Logger {
    public function log($message);
}

class FileLogger implements Logger {
    public function log($message) {
        file_put_contents('app.log', $message . PHP_EOL, FILE_APPEND);
    }
}

class DatabaseLogger extends FileLogger {
    public function log($message) {
        // запись в БД
        echo 'DB: ' . $message . PHP_EOL;
    }
}

$logger = new DatabaseLogger();
$logger->log('Test'); // DB: Test
?>
DB: Test

При наследовании часто возникает путаница с вызовом родительского конструктора – необходимо явно вызывать parent::__construct().

Как обрабатывать ошибки с помощью исключений?

В PHP 5 появилась поддержка исключений через try, catch, throw. Исключения позволяют централизованно обрабатывать ошибки.

<?php
function divide($a, $b) {
    if ($b == 0) {
        throw new InvalidArgumentException('Деление на ноль');
    }
    return $a / $b;
}

try {
    echo 'Результат: ' . divide(10, 2) . PHP_EOL;
    echo divide(10, 0);
} catch (InvalidArgumentException $e) {
    echo 'Ошибка: ' . $e->getMessage() . PHP_EOL;
}
?>
Результат: 5
Ошибка: Деление на ноль

Ошибка: catch должен перехватывать конкретный класс исключения, иначе необработанные исключения приводят к фатальной ошибке. Рекомендуется добавлять блок catch (Exception $e) для всех остальных.

Как безопасно работать с базами данных через PDO?

PDO (PHP Data Objects) предоставляет единый интерфейс для работы с разными СУБД и защищает от SQL-инъекций через подготовленные запросы.

<?php
$dsn = 'mysql:host=localhost;dbname=test;charset=utf8';
$user = 'root';
$password = '';

try {
    $pdo = new PDO($dsn, $user, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
    $stmt->execute(['email' => 'user@example.com']);
    $user = $stmt->fetch(PDO::FETCH_ASSOC);
    print_r($user);
} catch (PDOException $e) {
    echo 'Ошибка подключения: ' . $e->getMessage();
}
?>
Array ( [id] => 1 [name] => ... )

Частая ошибка – использование PDO::query() без экранирования параметров. Всегда использовать подготовленные запросы для пользовательского ввода.

Как перегрузить доступ к свойствам и методам через магические методы?

Магические методы __get, __set, __call позволяют обрабатывать обращения к несуществующим свойствам/методам.

<?php
class Config {
    private $data = [];
    
    public function __set($name, $value) {
        $this->data[$name] = $value;
    }
    
    public function __get($name) {
        return $this->data[$name] ?? null;
    }
    
    public function __call($name, $arguments) {
        if ($name === 'get') {
            return $this->data[$arguments[0]] ?? null;
        }
    }
}

$cfg = new Config();
$cfg->host = 'localhost';
echo $cfg->host . PHP_EOL;
echo $cfg->get('host');
?>
localhost
localhost

Магические методы работают только для несуществующих свойств/методов. Если свойство объявлено, но private, то __get не срабатывает. Не следует злоупотреблять магией – она замедляет выполнение и усложняет отладку.

Как создать анонимную функцию (замыкание) в PHP 5.3+?

Начиная с PHP 5.3, появились замыкания (closures). Они могут захватывать переменные из внешней области видимости с помощью ключевого слова use.

<?php
$factor = 2;
$multiply = function($x) use ($factor) {
    return $x * $factor;
};

echo $multiply(5) . PHP_EOL;

// Замыкание как callback для array_map
$numbers = [1, 2, 3];
$result = array_map($multiply, $numbers);
print_r($result);
?>
10
Array ( [0] => 2 [1] => 4 [2] => 6 )

Ошибка: забыть указать use – тогда внешняя переменная недоступна внутри замыкания. Также замыкания нельзя сериализовать.

Расширенные примеры использования PHP 5

Здесь представлены более сложные и неочевидные возможности PHP 5: трейты, позднее статическое связывание, Reflection API, итераторы SPL.

Пример 1: Трейты (PHP 5.4+)

Пример
<?php
trait LoggerTrait {
    public function log($msg) {
        echo '[LOG] ' . $msg . PHP_EOL;
    }
}

class Application {
    use LoggerTrait;
}

$app = new Application();
$app->log('Запуск приложения');
?>
[LOG] Запуск приложения

Пример 2: Позднее статическое связывание (Late Static Binding)

Пример
<?php
class Base {
    public static function who() {
        echo __CLASS__ . PHP_EOL;
    }
    
    public static function test() {
        static::who(); // позднее статическое связывание
    }
}

class Child extends Base {
    public static function who() {
        echo __CLASS__ . PHP_EOL;
    }
}

Child::test(); // Child, а не Base
?>
Child

Пример 3: Reflection API – анализ классов

Пример
<?php
class MyClass {
    public $publicProp;
    protected $protectedProp;
    private $privateProp;
    
    public function myMethod($arg) {}
}

$ref = new ReflectionClass('MyClass');
$properties = $ref->getProperties();
foreach ($properties as $prop) {
    echo $prop->getName() . ' : ' . $prop->getModifiers() . PHP_EOL;
}
?>
publicProp : 256
protectedProp : 512
privateProp : 1024

Пример 4: Итераторы SPL – DirectoryIterator

Пример
<?php
$dir = new DirectoryIterator('.');
foreach ($dir as $file) {
    if ($file->isFile()) {
        echo $file->getFilename() . ' (' . $file->getSize() . ' байт)' . PHP_EOL;
    }
}
?>
index.php (1234 байт)
style.css (567 байт)
...

Пример 5: Использование ключевого слова final для методов и классов

Пример
<?php
class Base {
    final public function cannotOverride() {
        echo 'Финализированный метод' . PHP_EOL;
    }
}

class Child extends Base {
    // Ошибка: нельзя переопределить final метод
    // public function cannotOverride() { }
}
?>
Fatal error: Cannot override final method Base::cannotOverride()

PHP 5 - comments

En
язык php 5 (php)