for93t

Рейтинг
104
Регистрация
13.04.2008
Должность
Webdeveloper @Spamexperts B.V.
ivan-lev:
Константа - не свойство объекта, а заранее заданное выражение ("захардкожено" до начала выполнения скрипта).. И задать её при инициализации объекта не получится :) даже формально..

Ну если придираться к словам, то у класса могут быть constants (константы), members (члены, переменные), methods (методы), а все вместе они - class properties - т.е. свойства класса, которые его и определяют.

---------- Добавлено 07.06.2013 в 14:17 ----------

Константа - не свойство объекта, а свойство класса.

ivan-lev:
for93t, на всякий случай.. Подход понимаю, но пытаюсь донести, что /на мой взгляд/ он не всегда является приемлемым и/или оптимальным. Особенно, если речь про работу с данными, получаемыми от пользователя. C ValueObject - Вполне логично, что если хост для подключения к DB указан неверно, то и смысла создавать соединение нет.

А я и не претендую на то, что озвучил истину во всех инстанциях :) Мой совет по использованию private-свойств относится к конкретной проблеме, которую озвучил ТС:

kiowas:
К тому же если я создаю класс, то в конструкторе уже какие-то свойства класса проверяются и вроде бы этого должно быть достаточно, но нет же... Первый же вызов метода из конструктора и меня опять клонит в этом методе все переменные перепроверить.... А вдруг в конструкторе не проверилось?

Если применить озвученный мной подход, то можно быть уверенным, что экземпляр класса содержит корректное значение свойства и можно не беспокоиться, вызывая методы, работающие с ним.

---------- Добавлено 07.06.2013 в 13:43 ----------

ortegas:
for93t, а еще можно использовать константы, в случае если она задается раз и навсегда.

Боюсь, ТС работает с user input, поэтому константы тут не помогут.

Хотя формально

kiowas:
свойство в объекте, которое будет доступно для чтения из вне, но не доступно для изменения из вне?

и есть определение константы класса.

kiowas:
Ок. Переформулирую вопрос. Есть ли возможность создать свойство в объекте, которое будет доступно для чтения из вне, но не доступно для изменения из вне?

Да, такое свойство должно иметь модификатор доступа private (или protected, если есть классы-потомки, которые работают с этим свойством) и чтение его значения извне должно осуществляться с помощью public-геттера.

kiowas:
Есть ли возможность защитить от изменения публичное свойство объекта?

Публичное свойство по определению нельзя защитить от прямых изменений - на то оно и публичное, что каждый может его читать и изменять.

kiowas:
Если появляется идея каким-то образом написать функцию или переопределить какую-то другую, так чтобы она была видна из любого куска скрипта и проверяла переменную на целое число положительно, в этом случае как лучше поступить? Как переопределить или создать свою функцию?

Простая глобальная функция (function isId($input) { ... }) будет видна из любой точки скрипта, если будет несколько таких функций, можно сделать их статическими методами какого-либо класса:


class Validator {
static final public function isId($input) { ... }
static final public function isEmail($input) { ... }
...
}

, но это не панацея, потому что вместо кучи проверок типа is_numeric(), !empty() и т.п. вы будете писать кучу проверок типа Validator::isId(). Это немного сократит код, но не устранит проблему. Нужно изолировать данные и делать доступ к ним контролируемым, для этого (в т.ч.) и была придумана инкапсуляция.

ivan-lev:
Пользователю в "цивильном" виде сообщать..

С отображением ему формы ввода.. с теми же данными, которые он ввёл на предыдущем шаге.. и подсветкой ошибки по соседству с полем, в котором ошибка.

Цивильное отображение - это уровень View, а валидация - уровень модели. Вьюхе, грубо говоря, все равно, как происходит проверка данных, ей важно получить список сообщений об ошибках и инструкции, куда их вставлять. А как был сформирован этот список - через исключения, возвращение false или прямым инжектом в какой-нибудь инстанс-коллектор сообщений - View может, точнее должен, не знать.

ivan-lev:
А чего ж сразу про сеттер не написать?

ИМХО, гиблый подход.. смешивать конструктор/сеттеры и валидацию.

Думаю, корректнее выносить валидацию в отдельный метод, в котором (в зависимости от задачи либо проверять все поля сразу, либо до первой ошибки) а вызывать явно в контроллере или неявно из методов модели. /Хотя, вполне возможно, иногда такой подход может быть оправданным.../

Я привел в пример класс, который реализует паттерн ValueObject. Для таких классов нет смысла создавать инстанс с заведомо неправильным значением какого-либо поля, поэтому бросание исключение там вполне уместно.

Валидация данных в модели крайне желательна, поскольку с одной и той же моделью может работать несколько контроллеров и в каждом потребуется делать валидацию, если этого не будет делать модель, а это дублирование кода со всеми вытекающими.

---------- Добавлено 07.06.2013 в 00:49 ----------

ivan-lev:
ИМХО, гиблый подход.. смешивать конструктор/сеттеры и валидацию

Вот тут вы ошибаетесь. Если public-сеттер работает с private переменной, он содержит логику валидации значений для этой переменной и существует соглашение о том, что извне задать значение переменной класса можно только с помощью этого метода, то получается единая точка ввода, которая гарантирует, что данная переменная всегда будет иметь корректное значение (или не иметь его вовсе, т.е. быть null). Такой подход очень распространен в серьезных приложениях/фреймворках. Если вы посмотрите в исходный код ZF, Symfony, Yii и т.п., то обязательно увидите примеры таких сеттеров. Самый упрощенный пример - это сеттер с type hint'ом для аргумента, где type hint как раз служит валидатором. Думаю, таких примеров можно найти предостаточно в любом "неговнокоде" на PHP.

ivan-lev:
эм.. а если надо задать "по ходу".. не в конструкторе?

Тогда нужно сделать public setter-метод, запрограммировать в нем валидацию и использовать его в конструкторе для установки значения переменной класса.

ivan-lev:
Вы реально так делаете? Можно кусок кода?

Если значение переменной класса критично для функционирования всего класса, то да, я реально так делаю. Пример кода:


class Core_Dns_Mx_Route
{
/**
* Hostname
*
* @access private
* @var string
*/
private $_host;

/**
* Class constructor
*
* @access public
*
* @param string $host
* @param int $priority
* @param int $port
*
* @throws Core_Dns_Exception
* @return Core_Dns_Mx_Route
*/
public function __construct($host, $priority = 10, $port = 25)
{
if (!Zend_Validate::is($host, 'Hostname', array('allow' => Zend_Validate_Hostname::ALLOW_DNS + Zend_Validate_Hostname::ALLOW_IP + Zend_Validate_Hostname::ALLOW_LOCAL))) {
throw new Core_Dns_Exception(
escsprintf(_("MX hostname '%s' is invalid. It should be either valid DNS hostname or valid IP address"), $host)
);
}
ivan-lev:
Валидатор он на то и валидатор, чтобы "проверять" (возвращать тру/не тру + получать список ошибок) , а не исключения кидать.

А что вы предлагаете дальше делать с тру/не тру?

Попробую свои непрокачанные навыки телепата...

SELECT * FROM `statti` WHERE `title` LIKE '%запрос%'

Предварительно нужно убедиться, что используемые кодировки совпадают.

kiowas:
К тому же если я создаю класс, то в конструкторе уже какие-то свойства класса проверяются и вроде бы этого должно быть достаточно, но нет же... Первый же вызов метода из конструктора и меня опять клонит в этом методе все переменные перепроверить.... А вдруг в конструкторе не проверилось?

Чтобы быть спокойным относительно переменных класса, их нужно делать private и задавать значения только через конструктор и только там делать валидацию. Если валидация не проходит, то конструктор должен бросать исключение. Для правильной валидации существуют такие библиотеки, как, например, Zend Validate - поначалу использование таких решений может выглядеть избыточно, но когда набивается достаточно шишек на собственных велосипедах, приходишь к выводу, что ничего особо лишнего на самом деле там нет.

Всего: 67