Свойства с модификатором доступа public в PHP: подробное описание
Основные приемы работы с public свойствами в PHP
Основное и наиболее эффективное решение: объявление public свойства с явным указанием типа (начиная с PHP 7.4) и значением по умолчанию, если это уместно. Прямой доступ через оператор -> позволяет читать и изменять свойство без дополнительных методов. Такой подход подходит для простых данных, не требующих валидации или логики при установке.
<?php
class User {
public string $name = 'Гость';
public int $age;
}
$user = new User();
$user->name = 'Анна'; // запись
$user->age = 25;
echo $user->name . ', ' . $user->age; // чтение
?>
классы в php файлы (определение классов в php-файлах)
Анна, 25
Php public var (public свойства класса в php)
Как объявить свойство без указания типа?
Используется ключевое слово var или public без типа. Ранний стиль (PHP 4) - var, но современная практика - применять public с типом.
<?php
class Product {
public $price; // без типа
var $title; // устаревший вариант
}
$p = new Product();
$p->price = 99.99;
?>
Php get set (геттеры и сеттеры в php)
Типичная ошибка: отсутствие типа может привести к передаче некорректных данных (например, строки вместо числа). Решение: с PHP 7.4+ рекомендуется всегда указывать тип. Исключение - случаи, когда свойство может принимать разные типы (тогда используется mixed или объединение типов).
Какие цели преследует такой вариант?
Обратная совместимость с кодом, написанным до PHP 7.4, или работа со свойствами, чей тип заранее не определён.
Как задать значение по умолчанию при объявлении?
Значение присваивается прямо в объявлении свойства. Допустимы константные выражения: числа, строки, массивы, null.
<?php
class Config {
public string $siteName = 'Мой сайт';
public int $port = 8080;
public array $allowedRoles = ['admin', 'user'];
public ?float $discount = null;
}
?>
Php method name (имя метода в php)
Проблема: нельзя использовать выражения, зависящие от времени выполнения (функции, new, ternary). Например, public $date = date('Y'); вызовет синтаксическую ошибку. Решение: инициализация в конструкторе.
Когда применяется?
Для фиксированных настроек, констант уровня класса или значений, не требующих вычислений при создании объекта.
Как получить доступ к public свойству внутри методов того же класса?
Используется $this->свойство. Конструкция $this ссылается на текущий объект.
<?php
class Counter {
public int $count = 0;
public function increment(): void {
$this->count++;
}
public function show(): int {
return $this->count;
}
}
$c = new Counter();
$c->increment();
echo $c->show();
?>
1
Ошибка новичков: попытка обратиться к свойству без $this (например, $count++ внутри метода). Это создаёт локальную переменную, а не изменяет свойство объекта. Решение: всегда использовать $this-> для обращения к свойствам/методам текущего объекта.
Как изменить public свойство извне класса?
Прямое присваивание через оператор -> на экземпляре объекта.
<?php
class Point {
public float $x = 0.0;
public float $y = 0.0;
}
$p = new Point();
$p->x = 10.5;
$p->y = -3.2;
echo "x={$p->x}, y={$p->y}";
?>
x=10.5, y=-3.2
Риск: отсутствие контроля над присваиваемым значением. Если позже потребуется добавить валидацию, придётся заменять прямое свойство на геттер/сеттер, что сломает внешний код. Решение: изначально использовать приватные свойства с публичными методами доступа, если есть вероятность изменения логики.
Цель такого подхода?
Максимальная простота и производительность. Используется для данных, которые не требуют побочных эффектов при изменении (например, DTO, конфиги, простые структуры).
Как наследуются public свойства?
Public свойства доступны в дочерних классах напрямую и могут быть переопределены (значение по умолчанию или тип).
<?php
class Animal {
public string $sound = '...';
}
class Dog extends Animal {
// переопределяем значение
public string $sound = 'Woof';
}
$dog = new Dog();
echo $dog->sound;
?>
Woof
Нюанс: при переопределении тип свойства в дочернем классе должен быть совместим с родительским (или отсутствовать). С PHP 7.4 можно сузить тип? Нет, ковариантность типов не поддерживается для свойств. Тип должен быть таким же или более общим (на практике чаще оставляют тот же). Решение: при необходимости изменить тип - пересмотреть архитектуру или не переопределять свойство, а использовать методы.
Как работают public статические свойства?
Статические public свойства принадлежат классу, а не объекту. Доступ через ClassName::$property или $object::$property.
<?php
class MathUtils {
public static float $pi = 3.14159;
}
echo MathUtils::$pi;
?>
3.14159
Ошибка: попытка обратиться к статическому свойству через $this-> внутри метода объекта. Это вызовет ошибку, так как $this не определён в статическом контексте. Решение: использовать self::$property внутри класса или ClassName::$property снаружи.
Когда применяется?
Для общих констант (хотя лучше const), счётчиков экземпляров, разделяемых ресурсов.
Как использовать типизированные public свойства (PHP 7.4+)?
Тип указывается перед именем свойства. Поддерживаются скалярные типы, классы, интерфейсы, массивы, callable, mixed и т.д. Начиная с PHP 7.4 свойства могут быть объявлены с типом и без значения по умолчанию (тогда они неинициализированы, но при попытке чтения до присвоения - ошибка).
<?php
class Order {
public int $id;
public ?DateTimeImmutable $createdAt = null;
public array $items = [];
}
$order = new Order();
$order->id = 1;
$order->createdAt = new DateTimeImmutable();
var_dump($order);
?>
object(Order)#1 (3) { ["id"]=> int(1) ["createdAt"]=> object(DateTimeImmutable)#2 (0) { } ["items"]=> array(0) { } }
Проблема: если свойство объявлено с типом, но без значения по умолчанию, и его не инициализировать в конструкторе - при попытке чтения до присвоения выбрасывается TypeError. Решение: всегда инициализировать такие свойства в конструкторе или присваивать значение сразу при создании объекта.
Какая цель?
Повышение надёжности кода - PHP автоматически проверяет соответствие типа при присвоении. Исключаются случайные несоответствия.
Как сделать public свойство неизменяемым после инициализации (readonly)?
В PHP 8.1+ используется модификатор readonly вместе с public. Такое свойство можно установить только один раз (в конструкторе или при объявлении).
<?php
class User {
public readonly string $username;
public function __construct(string $username) {
$this->username = $username;
}
}
$u = new User('ivan');
echo $u->username;
// $u->username = 'new'; // Ошибка: cannot modify readonly property
?>
Ограничение: readonly свойство не может быть статическим; его тип обязан быть объявлен; объекты можно менять внутри (если свойство содержит объект, сам объект не заморожен). Рекомендация: для иммутабельных DTO использовать readonly в сочетании с конструктором.
Когда это нужно?
Для неизменяемых данных после создания объекта - идентификаторы, даты создания, конфигурационные значения.
Все эти варианты позволяют гибко управлять доступом к данным объекта, выбирая между простотой и контролем.
Расширенные примеры с public свойствами
<?php
// Пример 1: Комбинирование public свойств с конструктором и типизацией
class Book {
public string $title;
public string $author;
public int $year;
public float $price;
public function __construct(string $title, string $author, int $year, float $price) {
$this->title = $title;
$this->author = $author;
$this->year = $year;
$this->price = $price;
}
}
$book = new Book('PHP для начинающих', 'Иван Петров', 2024, 1500.00);
echo "{$book->title} ({$book->year}) - {$book->price} руб.";
?>
PHP для начинающих (2024) - 1500 руб.
<?php
// Пример 2: Public свойства и трейты
trait Timestampable {
public DateTimeImmutable $createdAt;
public ?DateTimeImmutable $updatedAt = null;
}
class Post {
use Timestampable;
public string $content;
public function __construct(string $content) {
$this->content = $content;
$this->createdAt = new DateTimeImmutable();
}
}
$post = new Post('Текст поста');
echo $post->createdAt->format('Y-m-d H:i:s');
?>
2025-04-05 12:30:00 (текущая дата)
<?php
// Пример 3: Public static свойство как счётчик экземпляров
class Event {
public static int $counter = 0;
public string $name;
public function __construct(string $name) {
$this->name = $name;
self::$counter++;
}
}
$e1 = new Event('Событие 1');
$e2 = new Event('Событие 2');
echo "Создано экземпляров: " . Event::$counter;
?>
Создано экземпляров: 2
<?php
// Пример 4: Public свойства с объединёнными типами (PHP 8.0+)
class Flexible {
public int|string $id;
public ?float $score = null;
}
$f = new Flexible();
$f->id = 123;
$f->score = 4.5;
echo $f->id . ' - ' . $f->score;
?>
123 - 4.5
<?php
// Пример 5: Public свойства в анонимных классах
$obj = new class {
public string $message = 'Привет из анонимного класса!';
};
echo $obj->message;
?>
Привет из анонимного класса!
<?php
// Пример 6: Public свойства и Reflection (изменение через API)
class Secret {
public string $data = 'конфиденциально';
}
$ref = new ReflectionProperty('Secret', 'data');
$ref->setAccessible(true); // для private, но public и так доступен
$obj = new Secret();
echo $ref->getValue($obj);
?>
конфиденциально
<?php
// Пример 7: Public свойства и сериализация (json)
class Car {
public string $brand;
public string $model;
public int $year;
public function __construct(string $brand, string $model, int $year) {
$this->brand = $brand;
$this->model = $model;
$this->year = $year;
}
}
$car = new Car('Toyota', 'Camry', 2022);
echo json_encode($car, JSON_UNESCAPED_UNICODE);
?>
{"brand":"Toyota","model":"Camry","year":2022}
<?php
// Пример 8: Массив объектов и изменение public свойств
class Task {
public string $title;
public bool $completed = false;
}
$tasks = [
new Task(),
new Task(),
];
$tasks[0]->title = 'Купить молоко';
$tasks[0]->completed = true;
$tasks[1]->title = 'Позвонить другу';
foreach ($tasks as $task) {
echo "{$task->title}: " . ($task->completed ? 'выполнено' : 'не выполнено') . "\n";
}
?>
Купить молоко: выполнено Позвонить другу: не выполнено
Примечание к примерам:
Все примеры демонстрируют различные сценарии использования public свойств: от простых структур до интеграции с трейтами, статическими счётчиками и рефлексией. При работе с public свойствами важно помнить, что любые изменения видны всем потребителям объекта, поэтому для данных, требующих инвариантов, лучше использовать приватные свойства с методами доступа.