Объектно-ориентированное программирование: примеры классов и их использование в PHP
Основные подходы к созданию классов
Классы в PHP позволяют структурировать данные и поведение. Ниже рассмотрены разные способы их построения - от строгой инкапсуляции до динамического доступа. Каждый вариант сопровождается вопросом, который он решает.
Как спроектировать класс с надёжной инкапсуляцией данных?
Наиболее эффективный способ - использовать приватные свойства и публичные методы доступа (геттеры/сеттеры) с валидацией. Это гарантирует, что объект всегда находится в корректном состоянии.
class User {
private string $name;
private int $age;
public function __construct(string $name, int $age) {
$this->setName($name);
$this->setAge($age);
}
public function getName(): string {
return $this->name;
}
public function setName(string $name): void {
if ($name === '') {
throw new InvalidArgumentException('Name cannot be empty');
}
$this->name = $name;
}
public function getAge(): int {
return $this->age;
}
public function setAge(int $age): void {
if ($age < 0 || $age > 150) {
throw new InvalidArgumentException('Age must be between 0 and 150');
}
$this->age = $age;
}
}
$user = new User('Alice', 30);
echo $user->getName(); // Alice
классы в php файлы (определение классов в php-файлах)
Когда можно пожертвовать инкапсуляцией для ускорения разработки?
Если данные не требуют валидации (например, конфигурация), допустимо использовать публичные свойства. Это упрощает код и ускоряет написание, но нарушает инварианты.
class User {
public string $name;
public int $age;
}
$user = new User();
$user->name = 'Bob';
$user->age = 25;
Php interface файл (файл с php-интерфейсом (interface))
Как создать неизменяемый объект (DTO)?
Readonly свойства (PHP 8.1) позволяют задать значение один раз в конструкторе и запрещают последующие изменения. Подходит для передачи данных без побочных эффектов.
class User {
public function __construct(
public readonly string $name,
public readonly int $age
) {}
}
$user = new User('Charlie', 40);
// $user->name = 'Dave'; // Fatal error
Php примеры классов (примеры классов в php)
Как обеспечить гибкий доступ к свойствам без явного объявления каждого?
Магические методы __get и __set позволяют перехватывать чтение/запись необъявленных свойств. Это полезно для обёрток (прокси), но снижает производительность и типобезопасность.
class User {
private array $data = [];
public function __get(string $key): mixed {
return $this->data[$key] ?? null;
}
public function __set(string $key, mixed $value): void {
$this->data[$key] = $value;
}
}
$user = new User();
$user->name = 'Diana';
echo $user->name; // Diana
Php get set (геттеры и сеттеры в php)
Как создать иерархию классов с общим интерфейсом?
Наследование и интерфейсы позволяют строить полиморфные структуры. Абстрактные классы задают базовую функциональность, а интерфейсы - контракты.
interface Animal {
public function makeSound(): string;
}
abstract class Mammal implements Animal {
abstract public function makeSound(): string;
public function breathe(): string {
return 'Breathing';
}
}
class Dog extends Mammal {
public function makeSound(): string {
return 'Woof!';
}
}
$dog = new Dog();
echo $dog->makeSound(); // Woof!
Расширенные примеры классов
Класс с магическим методом __invoke
Позволяет использовать объект как функцию. Удобно для callback-замыканий.
class Multiplier {
private int $factor;
public function __construct(int $factor) {
$this->factor = $factor;
}
public function __invoke(int $value): int {
return $value * $this->factor;
}
}
$double = new Multiplier(2);
echo $double(5); // 10
Класс-одиночка (Singleton)
Гарантирует единственный экземпляр класса. Часто используется для подключения к базе данных.
class Database {
private static ?self $instance = null;
private PDO $pdo;
private function __construct() {
$this->pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
}
public static function getInstance(): self {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function getPdo(): PDO {
return $this->pdo;
}
}
$db = Database::getInstance();
Класс, реализующий Iterator для обхода коллекции
Позволяет использовать объект в цикле foreach.
class NumberCollection implements Iterator {
private array $numbers;
private int $position = 0;
public function __construct(array $numbers) {
$this->numbers = array_values($numbers);
}
public function current(): mixed {
return $this->numbers[$this->position];
}
public function key(): int {
return $this->position;
}
public function next(): void {
$this->position++;
}
public function rewind(): void {
$this->position = 0;
}
public function valid(): bool {
return isset($this->numbers[$this->position]);
}
}
$collection = new NumberCollection([10, 20, 30]);
foreach ($collection as $value) {
echo $value . ' '; // 10 20 30
}
Класс с трейтом и изменением приоритета метода
Трейты позволяют переиспользовать методы. При конфликте можно указать, какой метод использовать.
trait Logger {
public function log(string $msg): void {
echo "[LOG] $msg\n";
}
}
trait DebugLogger {
public function log(string $msg): void {
echo "[DEBUG] $msg\n";
}
}
class Application {
use Logger, DebugLogger {
DebugLogger::log insteadof Logger;
}
}
$app = new Application();
$app->log('test'); // [DEBUG] test
Класс с конструктором, использующим именованные аргументы (PHP 8+)
Именованные аргументы улучшают читаемость, особенно при большом количестве параметров.
class User {
public function __construct(
private string $name,
private int $age,
private string $email = ''
) {}
}
$user = new User(age: 25, name: 'Eve', email: 'eve@example.com');
var_dump($user);
object(User)#1 (3) {
["name":"User":private] => string(3) "Eve"
["age":"User":private] => int(25)
["email":"User":private] => string(17) "eve@example.com"
}
Класс с union types и mixed (PHP 8+)
Типизация аргументов и возвращаемых значений становится более гибкой.
class Converter {
public function convert(int|string $value): int|string {
if (is_string($value)) {
return strlen($value);
}
return (string) $value;
}
}
$conv = new Converter();
echo $conv->convert('hello') . ' '; // 5
echo $conv->convert(42); // 42 (string)
5 42