EasyТеория3 min

Классы и объекты

class, new, свойства, методы, visibility

Объявление класса

<?php
declare(strict_types=1);

class User
{
    // Properties (attributes)
    public string $name;
    public int $age;
    protected string $email;
    private string $password;

    // Constructor
    public function __construct(string $name, int $age, string $email, string $password)
    {
        $this->name = $name;
        $this->age = $age;
        $this->email = $email;
        $this->password = $password;
    }

    // Method
    public function greet(): string
    {
        return "Hello, I'm {$this->name}, {$this->age} years old";
    }

    // Getter for protected property
    public function getEmail(): string
    {
        return $this->email;
    }
}

// Creating objects
$user = new User('Alice', 25, '[email protected]', 'secret');
echo $user->greet();  // Hello, I'm Alice, 25 years old
echo $user->name;     // Alice (public — accessible)
// echo $user->password; // Fatal error (private)

Модификаторы видимости (Visibility)

Модификатор Класс Наследники Извне
public Да Да Да
protected Да Да Нет
private Да Нет Нет
<?php
declare(strict_types=1);

class Account
{
    public string $holder = 'John';       // Accessible everywhere
    protected float $balance = 0.0;        // Class + children only
    private string $pin = '1234';          // This class only

    public function deposit(float $amount): void
    {
        $this->balance += $amount;         // OK — same class
        $this->validatePin();              // OK — same class
    }

    private function validatePin(): bool
    {
        return strlen($this->pin) === 4;
    }
}

class SavingsAccount extends Account
{
    public function getBalance(): float
    {
        return $this->balance;    // OK — protected accessible in child
        // return $this->pin;     // ERROR — private not accessible in child!
    }
}

$account = new Account();
echo $account->holder;    // OK — public
// echo $account->balance; // Fatal error — protected
// echo $account->pin;     // Fatal error — private

Ловушка экзамена: private свойства и методы недоступны в дочерних классах. protected — доступны в самом классе и его наследниках, но НЕ извне. Метод, объявленный как private, можно "переопределить" в дочернем классе, но это будет НОВЫЙ метод (не override).

Свойства

<?php
declare(strict_types=1);

class Product
{
    // Typed properties (PHP 7.4+)
    public string $name;
    public float $price;
    public ?string $description = null;  // Nullable with default

    // Default values
    public int $quantity = 0;
    public array $tags = [];
    public bool $active = true;

    // Readonly (PHP 8.1+)
    public readonly string $sku;

    // Static properties
    public static int $instanceCount = 0;

    public function __construct(string $name, float $price, string $sku)
    {
        $this->name = $name;
        $this->price = $price;
        $this->sku = $sku;
        self::$instanceCount++;
    }
}

$p = new Product('Widget', 9.99, 'WDG-001');
echo $p->name;              // Widget
echo Product::$instanceCount; // 1

// readonly — can only be set once
// $p->sku = 'NEW';  // Error: Cannot modify readonly property

Запомни: Типизированное свойство без значения по умолчанию находится в "неинициализированном" состоянии. Обращение к такому свойству до инициализации вызовет Error: Typed property must not be accessed before initialization.

Статические свойства и методы

<?php
declare(strict_types=1);

class Counter
{
    private static int $count = 0;

    public static function increment(): void
    {
        self::$count++;
    }

    public static function getCount(): int
    {
        return self::$count;
    }

    public function instanceMethod(): void
    {
        // Can access static from instance method
        echo self::$count;
        echo static::$count;  // Late static binding
    }
}

Counter::increment();
Counter::increment();
echo Counter::getCount();  // 2

// Static methods cannot use $this!
// $this refers to an instance, static has no instance

Константы класса

<?php
declare(strict_types=1);

class HttpStatus
{
    public const OK = 200;
    public const NOT_FOUND = 404;
    public const SERVER_ERROR = 500;

    // Typed constants (PHP 8.3+)
    public const string VERSION = '1.0';

    // Visibility on constants (PHP 7.1+)
    protected const SECRET_KEY = 'abc123';
    private const INTERNAL_VERSION = 42;
}

echo HttpStatus::OK;         // 200
echo HttpStatus::NOT_FOUND;  // 404

// Access via instance
$status = new HttpStatus();
echo $status::OK;             // 200

// Dynamic access
$class = HttpStatus::class;
echo $class::OK;              // 200
echo constant('HttpStatus::OK'); // 200

Создание и клонирование объектов

<?php
declare(strict_types=1);

class Config
{
    public array $settings = [];

    public function __construct(array $settings)
    {
        $this->settings = $settings;
    }
}

$config1 = new Config(['debug' => true]);

// Assignment copies the object HANDLE (not the object itself)
$config2 = $config1;
$config2->settings['debug'] = false;
echo $config1->settings['debug'] ? 'true' : 'false';  // false — SAME object!

// Clone creates a SHALLOW copy
$config3 = clone $config1;
$config3->settings['debug'] = true;
echo $config1->settings['debug'] ? 'true' : 'false';  // true — different object!
// But nested objects are still shared (shallow copy)!

Ловушка экзамена: Присваивание объекта ($b = $a) копирует ИДЕНТИФИКАТОР, а не объект. Оба указывают на один объект. clone создаёт ПОВЕРХНОСТНУЮ копию: скалярные свойства копируются, но объекты внутри остаются общими. Для глубокого копирования реализуйте __clone().

Анонимные классы (PHP 7.0+)

<?php
declare(strict_types=1);

// Anonymous class
$logger = new class {
    public function log(string $message): void
    {
        echo "[LOG] {$message}\n";
    }
};
$logger->log('Test');  // [LOG] Test

// With constructor and interface
interface LoggerInterface {
    public function log(string $message): void;
}

function createLogger(string $prefix): LoggerInterface
{
    return new class($prefix) implements LoggerInterface {
        public function __construct(private readonly string $prefix) {}

        public function log(string $message): void
        {
            echo "[{$this->prefix}] {$message}\n";
        }
    };
}

$logger = createLogger('APP');
$logger->log('Started');  // [APP] Started

Вопросы с экзамена ZCE

Проверь себя

5 из 75

Каковы значения `$a` в `$obj_one` и `$obj_two` при выполнении скрипта? ```php class myClass { private $a; public function __construct() { $this->a = 10; } public function printValue() { print "{$this->a},"; } public function changeValue($val, $obj = null) { if (is_null($obj)) { $this->a = $val; } else { $obj->a = $val; } } public function getValue() { return $this->a; } } $obj_one = new myClass(); $obj_two = new myClass(); $obj_one->changeValue(20, $obj_two); $obj_two->changeValue($obj_two->getValue(), $obj_one); $obj_two->printValue(); $obj_one->printValue(); ```

Какие утверждения верны для паттерна Registry? (Выберите 2)

Выберите все правильные варианты

Какова связь между классами и объектами?

Запись `self::$property` обращается к:

Как добавить книгу к существующему объекту `SimpleXMLElement`, хранящемуся в `$library`?

Code Challenges

Реализация стека

PHP

Реализуйте класс Stack с методами push(), pop(), peek() и isEmpty().

Test Cases

1. Input: push(1), push(2), peek()→ Expected: 2
2. Input: push(1), push(2), pop()→ Expected: 2
3. Input: isEmpty()→ Expected: true

Связный список

PHP

Реализуйте однонаправленный связный список с методами add(), remove(), find() и toArray().

Test Cases

1. Input: add(1), add(2), add(3), toArray()→ Expected: [1,2,3]
2. Input: add(1), add(2), remove(1), toArray()→ Expected: [2]
3. Input: add(5), find(5)→ Expected: true
4. Input: find(999)→ Expected: false

Очередь из двух стеков

PHP

Реализуйте очередь (FIFO) с использованием двух стеков. Методы: enqueue(), dequeue(), peek(), isEmpty().

Test Cases

1. Input: enqueue(1), enqueue(2), dequeue()→ Expected: 1
2. Input: enqueue(1), enqueue(2), enqueue(3), peek()→ Expected: 1
3. Input: isEmpty()→ Expected: true
4. Input: enqueue(1), dequeue(), isEmpty()→ Expected: true