PHP - мой первый язык программирования. Я не могу полностью понять, когда использовать статические классы против созданных объектов.
Я понимаю, что вы можете дублировать и клонировать объекты. Однако все время, когда я использовал php, любой объект или функция всегда заканчивались как одно возвращаемое (массив, строка, int) значение или пустота.
Я понимаю такие понятия в книгах, как класс персонажей видеоигр. продублируйте автомобильный объект и сделайте новый красный , что все имеет смысл, но не его применение в php и веб-приложениях.
Простой пример Блог. Какие объекты блога лучше всего реализовать в виде статических или созданных объектов? Класс БД? Почему бы просто не создать экземпляр объекта db в глобальной области видимости? Почему бы не сделать каждый объект статичным? Как насчет производительности?
Это все просто стиль? Есть ли правильный способ сделать это?
Основными двумя причинами против использования статических методов являются:
Наличие статического вызова метода внутри какого-либо другого метода на самом деле хуже, чем импорт глобальной переменной. В PHP классы являются глобальными символами, поэтому каждый раз, когда вы вызываете статический метод, вы полагаетесь на глобальный символ (имя класса). Это тот случай, когда глобальное зло. У меня были проблемы с такого рода подходом с некоторым компонентом Zend Framework. Существуют классы, которые используют статические вызовы методов (фабрики) для построения объектов. Для меня было невозможно поставить другую фабрику для этого экземпляра, чтобы получить настроенный объект. Решение этой проблемы состоит в том, чтобы использовать только экземпляры и методы instace и применять одиночные символы и т.п. в начале программы.
У Мишко Хевери , который работает в Agile Coach в Google, есть интересная теория, или, точнее, совет, что мы должны отделить время создания объекта от времени, когда мы его используем. Таким образом, жизненный цикл программы делится на две части. Первая часть (
main()
скажем, метод), которая заботится обо всей связке объектов в вашем приложении и части, которая выполняет реальную работу.Поэтому вместо того, чтобы:
Мы должны сделать:
И затем, на индексной / главной странице, мы сделали бы (это шаг связывания объекта или время для создания графа экземпляров, которые будут использоваться программой):
Основная идея состоит в том, чтобы отделить зависимости от ваших классов. Таким образом, код становится гораздо более расширяемым и, что наиболее важно для меня, тестируемым. Почему важнее быть тестируемым? Поскольку я не всегда пишу код библиотеки, поэтому расширяемость не так важна, но тестирование важно, когда я делаю рефакторинг. В любом случае, тестируемый код обычно дает расширяемый код, так что на самом деле это не так.
Мишко Хевери также проводит четкое различие между синглетонами и синглетонами (с большой буквы или без нее). Разница очень простая. Синглтоны с нижним регистром "s" приводятся в действие проводкой в index / main. Вы создаете экземпляр объекта класса, который не реализует шаблон Singleton, и заботитесь о том, чтобы передать этот экземпляр только любому другому экземпляру, который нуждается в нем. С другой стороны, синглтон с большой буквы «S» является реализацией классического (анти) паттерна. В основном замаскированный глобал, который не имеет большого применения в мире PHP. Я не видел ни одного до этого момента. Если вы хотите, чтобы все ваши классы использовали соединение с одной БД, лучше сделать это следующим образом:
Делая вышеизложенное, становится ясно, что у нас есть синглтон, и у нас также есть хороший способ добавить макет или заглушку в наших тестах. Удивительно, как юнит-тесты приводят к лучшему дизайну. Но это имеет большой смысл, когда вы думаете, что тесты заставляют задуматься о том, как вы будете использовать этот код.
Единственная ситуация, в которой я бы использовал (и я использовал их для имитации объекта-прототипа JavaScript в PHP 5.3) статические члены, - это когда я знаю, что соответствующее поле будет иметь одно и то же значение в перекрестном экземпляре. В этот момент вы можете использовать статическое свойство и, возможно, пару статических методов получения / установки. В любом случае, не забудьте добавить возможность переопределения статического члена элементом экземпляра. Например, Zend Framework использовал статическое свойство, чтобы указать имя класса адаптера БД, используемого в экземплярах
Zend_Db_Table
. Прошло некоторое время с тех пор, как я их использовал, поэтому, возможно, это уже не актуально, но вот как я это помню.Статические методы, которые не имеют дело со статическими свойствами, должны быть функциями. У PHP есть функции, и мы должны их использовать.
источник
Так что в PHP статика может применяться к функциям или переменным. Нестатические переменные связаны с конкретным экземпляром класса. Нестатические методы действуют на экземпляр класса. Итак, давайте составим класс с именем
BlogPost
.title
будет нестатичным членом. Он содержит заголовок этого сообщения в блоге. У нас также может быть метод с именемfind_related()
. Это не статично, потому что это требует информации от определенного экземпляра класса сообщения блога.Этот класс будет выглядеть примерно так:
С другой стороны, используя статические функции, вы можете написать такой класс:
В этом случае, поскольку функция является статической и не действует на какой-либо конкретный пост в блоге, вы должны передать этот пост в качестве аргумента.
По сути это вопрос объектно-ориентированного проектирования. Ваши классы - это существительные в вашей системе, а функции, действующие на них, - это глаголы. Статические функции являются процедурными. Вы передаете объект функций в качестве аргументов.
Обновление: я бы также добавил, что решение редко делается между методами экземпляра и статическими методами, и больше между использованием классов и ассоциативных массивов. Например, в приложении для ведения блога вы либо читаете записи блога из базы данных и конвертируете их в объекты, либо оставляете их в наборе результатов и рассматриваете их как ассоциативные массивы. Затем вы пишете функции, которые принимают ассоциативные массивы или списки ассоциативных массивов в качестве аргументов.
В сценарии OO вы пишете методы для вашего
BlogPost
класса, которые действуют на отдельные сообщения, и вы пишете статические методы, которые действуют на коллекции сообщений.источник
Долгий путь, да. Вы можете написать очень хорошие объектно-ориентированные программы, даже не используя статические члены. На самом деле некоторые люди утверждают, что статические элементы - это, в первую очередь, примесь. Я хотел бы предложить, - как новичок в oop - вы стараетесь избегать статических членов все вместе. Это заставит вас писать в объектно-ориентированном, а не процедурном стиле.
источник
У меня другой подход к большинству ответов здесь, особенно при использовании PHP. Я думаю, что все классы должны быть статическими, если у вас нет веских причин, почему нет. Вот некоторые из причин «почему нет»:
Позвольте мне привести один пример. Поскольку каждый PHP-скрипт генерирует HTML-код, у моего фреймворка есть класс писателя html. Это гарантирует, что никакой другой класс не будет пытаться писать HTML, поскольку это специализированная задача, которая должна быть сосредоточена в одном классе.
Как правило, вы бы использовали класс html следующим образом:
Каждый раз, когда вызывается get_buffer (), он сбрасывает все, так что следующий класс, использующий средство записи html, запускается в известном состоянии.
Все мои статические классы имеют функцию init (), которую необходимо вызвать перед первым использованием класса. Это больше условно, чем необходимость.
Альтернатива статическому классу в этом случае грязная. Вы не хотели бы, чтобы каждый класс, которому нужно написать чуть-чуть html, должен был управлять экземпляром средства записи html.
Теперь я дам вам пример, когда не следует использовать статические классы. Мой класс формы управляет списком элементов формы, таких как ввод текста, раскрывающиеся списки и многое другое. Обычно используется так:
Нет никакого способа сделать это со статическими классами, особенно если учесть, что некоторые конструкторы каждого добавленного класса выполняют большую работу. Также цепочка наследования для всех элементов довольно сложная. Так что это яркий пример, где статические классы не должны использоваться.
Большинство служебных классов, таких как те, которые преобразуют / форматируют строки, являются хорошими кандидатами на роль статического класса. Мое правило простое: в PHP все идет статично, если только нет одной причины, почему это не следует делать.
источник
«Наличие статического вызова метода внутри какого-то другого метода на самом деле хуже, чем импорт глобальной переменной». (определить «хуже») ... и «Статические методы, которые не имеют дело со статическими свойствами, должны быть функциями».
Это оба довольно широкие заявления. Если у меня есть набор функций, связанных по предмету, но данные экземпляра совершенно неуместны, я бы предпочел, чтобы они были определены в классе, а не в каждой из них в глобальном пространстве имен. Я просто использую механику, доступную в PHP5 для
это всего лишь удобный способ обеспечить более высокое сцепление и более низкую связь.
И FWIW - в PHP 5 нет такой вещи, как «статические классы»; методы и свойства могут быть статическими. Чтобы предотвратить создание экземпляров класса, можно также объявить его абстрактным.
источник
Сначала спросите себя, что этот объект будет представлять? Экземпляр объекта хорош для работы с отдельными наборами динамических данных.
Хорошим примером будет ORM или уровень абстракции базы данных. У вас может быть несколько подключений к базе данных.
Эти два соединения теперь могут работать независимо:
Теперь в этом пакете / библиотеке могут быть другие классы, такие как Db_Row и т. Д., Которые представляют конкретную строку, возвращаемую из инструкции SELECT. Если бы этот класс Db_Row был статическим классом, то это означало бы, что у вас есть только одна строка данных в одной базе данных, и было бы невозможно сделать то, что мог сделать экземпляр объекта. С экземпляром вы можете теперь иметь неограниченное количество строк в неограниченном количестве таблиц в неограниченном количестве баз данных. Единственным ограничением является серверное оборудование;).
Например, если метод getRows объекта Db возвращает массив объектов Db_Row, теперь вы можете работать с каждой строкой независимо друг от друга:
Хорошим примером статического класса было бы то, что обрабатывает переменные реестра или переменные сеанса, поскольку на пользователя будет только один реестр или один сеанс.
В одной части вашего заявления:
И в другой части:
Поскольку в каждом сеансе будет только один пользователь, нет смысла создавать экземпляр для сеанса.
Я надеюсь, что это помогает, наряду с другими ответами, чтобы помочь прояснить ситуацию. Как примечание стороны, проверьте " сцепление " и " сцепление ". Они обрисовывают в общих чертах некоторые очень и очень хорошие практики, которые следует использовать при написании кода, которые применимы ко всем языкам программирования.
источник
Если ваш класс является статическим, это означает, что вы не можете передать его объект другим классам (так как экземпляр не возможен), что означает, что все ваши классы будут напрямую использовать этот статический класс, что означает, что ваш код теперь тесно связан с классом. ,
Тесная связь делает ваш код менее пригодным для повторного использования, хрупким и подверженным ошибкам. Вы хотите избежать статических классов, чтобы иметь возможность передавать экземпляр класса другим классам.
И да, это только одна из многих других причин, некоторые из которых уже упоминались.
источник
В общем, вы должны использовать переменные-члены и функции-члены, если только вы не должны делиться ими между всеми экземплярами или если вы создаете одиночный файл. Использование данных-членов и функций-членов позволяет вам повторно использовать свои функции для нескольких различных частей данных, в то время как у вас может быть только одна копия данных, с которой вы работаете, если используете статические данные и функции. Кроме того, хотя это не относится к PHP, статические функции и данные приводят к тому, что код не подлежит возврату, тогда как данные класса облегчают повторное поступление.
источник
Я хотел бы сказать, что есть определенный случай, когда я хотел бы использовать статические переменные - в мультиязычных приложениях. У вас может быть класс, которому вы передаете язык (например, $ _SESSION ['language']), и он, в свою очередь, обращается к другим классам, которые сконструированы следующим образом:
Использование Strings :: getString ("somestring") - это хороший способ абстрагировать использование языка от вашего приложения. Вы можете сделать это, как вам угодно, но в этом случае наличие каждого строкового файла, имеющего константы со строковыми значениями, к которым обращается класс Strings, работает довольно хорошо.
источник