Я не PHP-разработчик, поэтому мне интересно, если в PHP более популярно использовать явные методы получения / установки, в чистом стиле ООП, с закрытыми полями (как мне нравится):
class MyClass {
private $firstField;
private $secondField;
public function getFirstField() {
return $this->firstField;
}
public function setFirstField($x) {
$this->firstField = $x;
}
public function getSecondField() {
return $this->secondField;
}
public function setSecondField($x) {
$this->secondField = $x;
}
}
или просто публичные поля:
class MyClass {
public $firstField;
public $secondField;
}
Спасибо
php
oop
coding-style
отметка
источник
источник
Ответы:
Вы можете использовать магические методы php
__get
и__set
.источник
__get
и__set
. Есть два подчеркивания, а не одно. Вот прямая ссылка на правую часть страницы: php.net/manual/en/… (+1 для правильного ответа)public
собственности, если нет проверки / санитарии?Зачем использовать геттеры и сеттеры?
источник
Google уже опубликовал руководство по оптимизации PHP и сделал вывод:
Нет геттера и сеттера Оптимизация PHP
И нет, вы не должны использовать магические методы . Для PHP магический метод - зло. Зачем?
PHP не является Java, C ++ или C #. PHP отличается и играет с разными ролями.
источник
$dog->name = 'fido'
лучше чем$dog->setName('fido')
. При действительном изменении свойства (например,$dog->increaseAge(1)
я могу создать метод, который выполняет необходимую проверку и мутирует это свойство. Но не все действия действительно требуют мутации в этом смысле.Инкапсуляция важна в любом языке ОО, популярность не имеет к этому никакого отношения. В динамически типизированных языках, таких как PHP, это особенно полезно, поскольку существует мало способов убедиться, что свойство имеет определенный тип без использования установщиков.
В PHP это работает:
В Java это не так:
Использование магических методов (
__get
и__set
) также работает, но только при доступе к свойству, которое имеет более низкую видимость, чем текущая область. Он может легко вызвать головную боль при попытке отладки, если он не используется должным образом.источник
$bar
какint
в первом примере: wiki.php.net/rfc/typed_properties_v2Если вы предпочитаете использовать функцию __call, вы можете использовать этот метод. Работает с
$this->property()
$this->property($value)
$this->getProperty()
$this->setProperty($value)
kalsdas
источник
property_exists(get_class($this), $name)
а рекурсия медленная. Есть способ у смягчить это с помощью кэширования, но он все равно будет медленнее, чем создание методов получения и установки вручную. Я только написал это как альтернативу. Я на самом деле не рекомендую использовать «магические методы». Дополнительное время создания геттеров и сеттеров обычно незначительно.В дополнение к и без того отличным и уважаемым ответам здесь я хотел бы остановиться на PHP без установщиков / получателей.
В PHP нет синтаксиса геттера и сеттера . Он предоставляет подклассные или магические методы, позволяющие «перехватывать» и переопределять процесс поиска свойств, как указал Дэйв .
Магия позволяет нам ленивым программистам делать больше с меньшим количеством кода в то время, когда мы активно участвуем в проекте и знаем его глубоко, но обычно за счет читабельности.
Производительность Каждая ненужная функция, возникающая в результате принудительного использования PHP-архитектуры, подобной геттеру / сеттеру, при вызове использует свой собственный стековый фрейм памяти и тратит впустую циклы ЦП.
Читаемость: кодовая база вызывает вздутие живота кодовых строк, что влияет на навигацию по коду, так как больше LOC означает больше прокрутки.
Предпочтение: лично я, как правило, воспринимаю провал статического анализа кода как знак, позволяющий избежать перехода по волшебной дороге, если в то время мне не хватает очевидных долгосрочных преимуществ.
Заблуждения:
Распространенным аргументом является удобочитаемость. Например,
$someobject->width
это легче читать, чем$someobject->width()
. Однако в отличие от планетыcircumference
илиwidth
, что можно предположитьstatic
, экземпляр объекта, например$someobject
, для которого требуется функция ширины, скорее всего, измеряет ширину экземпляра объекта.Поэтому удобочитаемость повышается главным образом из-за утвержденных схем именования, а не из-за того, что функция скрывается, что выводит данное значение свойства.
__get / __set использует:
предварительная проверка и предварительная санация стоимости имущества
например, строки
В этом случае следует
generatelatex
придерживаться схемы именования actionname + methodnameособые, очевидные случаи
Примечание: PHP решил не реализовывать синтаксис getter / setter. Я не утверждаю, что геттеры / сеттеры вообще плохие.
источник
Готов!
источник
Ну, PHP имеет магические методы
__get
,__set
,__isset
и__unset
, всегда начало. Увы, правильные (понимаете?) Свойства ОО - это больше, чем магические методы. Основная проблема с реализацией PHP заключается в том, что магические методы вызываются для всех недоступных свойств. Это означает, что вы должны повторять себя (например, вызывая property_exists ()) в магических методах, когда определяете , действительно ли name является свойством вашего объекта. И вы не можете решить эту общую проблему с базовым классом, если все ваши классы не наследуются от ie. ClassWithProperties, поскольку в PHP отсутствует множественное наследование.Напротив, новые классы стилей Python предоставляют вам
property()
, что позволяет вам явно определять все ваши свойства. C # имеет специальный синтаксис.http://en.wikipedia.org/wiki/Property_(programming)
источник
Я провел эксперимент, используя магический метод __call. Не уверен, стоит ли мне это публиковать (из-за всех предупреждений «НЕ ИСПОЛЬЗУЙТЕ ВОЛШЕБНЫЕ МЕТОДЫ» в других ответах и комментариях), но я оставлю это здесь ... на всякий случай, если кто-то посчитает это полезным.
Просто добавьте этот метод выше в своем классе, теперь вы можете ввести:
Таким образом, вы можете получить / установить все в своем классе, если оно существует, поэтому, если вам это нужно только для нескольких конкретных элементов, вы можете использовать «белый список» в качестве фильтра.
Пример:
Теперь вы можете получить / установить только «foo» и «fee».
Вы также можете использовать этот «белый список» для назначения пользовательских имен для доступа к вашим переменным.
Например,
С этим списком вы можете напечатать:
,
,
,
Вот и все.
Doc: __call () срабатывает при вызове недоступных методов в контексте объекта.
источник
Прочитав другие советы, я склонен сказать, что:
Как ОБЩЕЕ правило, вы не всегда будете определять сеттеры для ВСЕХ свойств, особенно «внутренних» (семафоры, внутренние флаги ...). Очевидно, что свойства только для чтения не будут иметь установщиков, поэтому некоторые свойства будут иметь только получатели; вот где __get () сокращает код:
Да! мы могли бы написать частный метод, чтобы сделать это, но, опять же, мы будем иметь МНОГИЕ объявленные методы (++ memory), которые в конечном итоге вызовут другой, всегда один и тот же метод. Почему бы просто не написать ОДИН метод, чтобы управлять ими всеми ...? [Ага! каламбур абсолютно предназначен! :)]
Магические сеттеры также могут реагировать ТОЛЬКО на определенные свойства, поэтому все свойства типа даты могут быть проверены на наличие недопустимых значений только одним методом. Если свойства типа даты были перечислены в массиве, их установщики могут быть легко определены. Просто пример, конечно. Есть слишком много ситуаций.
О читабельности ... Ну ... Это еще одна дискуссия: мне не нравится связываться с использованием IDE (на самом деле, я не использую их, они, как правило, говорят мне (и заставляют меня), как пиши ... а мне нравятся кодировки "красота"). Я склонен быть последовательным в отношении именования, поэтому мне достаточно использования ctags и пары других вспомогательных средств ... В любом случае: как только все эти магические сеттеры и геттеры завершены, я пишу другие сеттеры, которые слишком специфичны или «особенные» для быть обобщенным в методе __set (). И это охватывает все, что мне нужно о получении и настройке свойств. Конечно: не всегда есть общий язык, или есть несколько таких свойств, которые не стоят проблем при кодировании магического метода, а есть еще старая добрая традиционная пара сеттер / геттер.
Языки программирования - это всего лишь человеческие искусственные языки. Итак, у каждого из них есть своя собственная интонация или акцент, синтаксис и вкус, поэтому я не буду притворяться, что пишу код на Ruby или Python, используя тот же «акцент», что и Java или C #, и я не написал бы JavaScript или PHP, чтобы они напоминали Perl или SQL ... Используйте их так, как они предназначены.
источник
Вообще говоря, первый способ в целом более популярен, потому что те, кто уже обладает знаниями в области программирования, могут легко перейти на PHP и выполнить работу объектно-ориентированным способом. Первый способ более универсален. Мой совет - придерживаться того, что проверено и верно на многих языках. Затем, когда и если вы будете использовать другой язык, вы будете готовы сделать что-то ( вместо того, чтобы тратить время на изобретение колеса ).
источник
Существует много способов создания исходного кода в соглашении netbeans. Это хорошо. Это делает мысли такими проще === ЛОЖЬ. Просто используйте традицию, особенно если вы не уверены, какое из свойств должно быть заключено в капсулу, а какое нет. Я знаю, что это код boi .... pla ..., но для отладки и многим другим он кажется лучшим и понятным. Не тратьте много времени на искусство, как делать простые добытчики и сеттеры. Вы не можете также реализовать некоторые шаблоны проектирования, такие как правило demeter и так далее, если вы используете магию. В конкретной ситуации вы можете использовать magic_calls или для небольших, быстрых и понятных решений. Конечно, вы могли бы также найти решения для дизайнеров, но зачем вам жить сложнее.
источник
Проверка + форматирование / получение значений
Установщики позволяют вам проверять данные, а получатели - форматировать или извлекать данные. Объекты позволяют вам инкапсулировать данные и их код для проверки и форматирования в аккуратный пакет, который поддерживает DRY.
Например, рассмотрим следующий простой класс, который содержит дату рождения.
Вы хотите проверить, что установленное значение
И вы не хотите выполнять эту проверку по всему вашему приложению (или по нескольким приложениям в этом отношении). Вместо этого проще сделать переменную-член защищенной или закрытой (чтобы сделать установщик единственной точкой доступа) и выполнить проверку в установщике, потому что тогда вы будете знать, что объект содержит действительную дату рождения независимо от того, какая часть приложение, из которого получен объект, и если вы хотите добавить дополнительную проверку, вы можете добавить его в одном месте.
Вы можете добавить несколько форматтеров , которые работают на одной и тот же переменном членом , т.е.
getAge()
и ,getDaysUntilBirthday()
и вы можете применять настраиваемый формат вgetBirthDate()
зависимости от региона. Поэтому я предпочитаю постоянный доступ к значениям через геттеры, а не к смешиванию$date->getAge()
с$date->birth_date
.геттеры и сеттеры также полезны при расширении объектов. Например, предположим, что ваше приложение должно разрешать 150+ лет рождения в некоторых местах, но не в других. Одним из способов решения проблемы без повторения какого-либо кода является расширение
BirthDate
объекта и добавление дополнительной проверки в установщик.источник
setHired
иsetHireDate
. Нельзя допускать, чтобы кто-то назначал дату найма, не назначая сотрудника как наемного. Но вы никоим образом не обеспечили это. Если вы применяете его в одном из этих сеттеров, то вы устанавливаете порядок «установки», а для этого требуется больше чтения кода от разработчика. Затем, когда вы идете, чтобы сделать метод, подобный,$employee->promote($newPosition);
вы должны проверить флаг, чтобы увидеть, была ли выполнена проверка, или предположить, что это не было сделано, и сделать это снова (избыточно).$employee->updateWorkStatus($hired, $hireDate);
или если более продвинутый$employee->adminUpdate(\Employee\AdminUpdateDTO $dto);
. Теперь вы можете проверить в нужном вам контексте и решить, нужна ли вообще дополнительная проверка.Это сообщение не конкретно о
__get
и__set
а__call
что та же идея метода вызова , за исключением. Как правило, я держусь подальше от любых магических методов, которые допускают перегрузку по причинам, изложенным в комментариях и сообщениях ОДНАКО , я недавно столкнулся с сторонним API, который я использую, который использует SERVICE и SUB-SERVICE, например :Важной частью этого является то, что в этом API есть все то же самое, за исключением вспомогательного действия, в данном случае
doActionOne
. Идея состоит в том, что разработчик (я и другие, использующие этот класс) могут вызывать вспомогательную службу по имени, а не что-то вроде:Я мог бы сделать вместо этого:
Для жесткого кодирования это было бы просто дублированием (этот пример очень похож на код):
Но с помощью волшебного метода
__call()
я могу получить доступ ко всем сервисам динамическими методами:Преимущество этого динамического вызова для возврата данных состоит в том, что если поставщик добавляет еще одну вспомогательную услугу, мне не нужно добавлять другой метод в класс или создавать расширенный класс и т. Д. Я не уверен, что это полезно для кто- нибудь, но я полагал , что я бы показать пример , где
__set
,__get
,__call
и т.д. , может быть вариантом для рассмотрения , так как основная функция является возвращением данных.РЕДАКТИРОВАТЬ:
По совпадению, я увидел это через несколько дней после публикации, которая в точности описывает мой сценарий. Это не тот API, о котором я говорил, но применение методов идентично:
Я правильно использую API?
источник
Обновление: не используйте этот ответ, так как это очень глупый код, который я нашел во время изучения. Просто используйте простой метод получения и установки, это намного лучше.
Я обычно использую это имя переменной в качестве имени функции и добавляю необязательный параметр к этой функции, чтобы, когда этот необязательный параметр заполнялся вызывающей стороной, затем устанавливал его в свойстве и возвращал $ this object (сцепление), а затем, когда этот необязательный параметр не указан вызывающий, я просто возвращаю свойство вызывающему.
Мой пример:
источник