Я получаю доступ к своей базе данных MySQL через PDO. Я настраиваю доступ к базе данных, и моей первой попыткой было использовать следующее:
Первое, о чем я подумал global
:
$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'root', 'pwd');
function some_function() {
global $db;
$db->query('...');
}
Это считается плохой практикой. После небольшого поиска я остановился на шаблоне Singleton , который
«применяется к ситуациям, в которых должен быть единственный экземпляр класса».
Согласно примеру в руководстве, мы должны сделать это:
class Database {
private static $instance, $db;
private function __construct(){}
static function singleton() {
if(!isset(self::$instance))
self::$instance = new __CLASS__;
return self:$instance;
}
function get() {
if(!isset(self::$db))
self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd')
return self::$db;
}
}
function some_function() {
$db = Database::singleton();
$db->get()->query('...');
}
some_function();
Зачем мне нужен этот относительно большой класс, если я могу это сделать?
class Database {
private static $db;
private function __construct(){}
static function get() {
if(!isset(self::$db))
self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd');
return self::$db;
}
}
function some_function() {
Database::get()->query('...');
}
some_function();
Последний работает отлично, и мне больше не о чем беспокоиться $db
.
Как я могу создать меньший одноэлементный класс, или есть вариант использования для синглтонов, который мне не хватает в PHP?
php
oop
design-patterns
singleton
серьезный дев
источник
источник
Ответы:
Хорошо, я задумывался над этим некоторое время, когда только начинал свою карьеру. Реализовал его по-разному и придумал две причины не использовать статические классы, но они довольно большие.
Во-первых, вы очень часто обнаруживаете то, чего абсолютно уверены в том, что у вас никогда не будет больше одного экземпляра, а в конечном итоге у вас будет второй. Вы можете получить второй монитор, вторую базу данных, второй сервер - что угодно.
Когда это происходит, если вы использовали статический класс, вам придется провести гораздо худший рефакторинг, чем если бы вы использовали синглтон. Синглтон сам по себе является сомнительным шаблоном, но он довольно легко преобразуется в интеллектуальный фабричный шаблон - его даже можно без особых проблем преобразовать для использования внедрения зависимостей. Например, если ваш синглтон получен через getInstance (), вы можете довольно легко изменить его на getInstance (databaseName) и разрешить использование нескольких баз данных - никаких других изменений кода.
Вторая проблема - это тестирование (и, честно говоря, это то же самое, что и первая проблема). Иногда вы хотите заменить свою базу данных фиктивной. Фактически это второй экземпляр объекта базы данных. Это намного сложнее сделать со статическими классами, чем с синглтоном, вам нужно только имитировать метод getInstance (), а не каждый отдельный метод в статическом классе (что на некоторых языках может быть очень сложным).
На самом деле все сводится к привычкам - и когда люди говорят, что «глобалы» - это плохо, у них есть очень веские причины так говорить, но это не всегда будет очевидно, пока вы сами не решите проблему.
Лучшее, что вы можете сделать, - это спросить (как вы это сделали), а затем сделать выбор и наблюдать за последствиями своего решения. Знание, позволяющее интерпретировать эволюцию вашего кода с течением времени, гораздо важнее, чем делать это правильно с самого начала.
источник
getInstance(databaseName)
прежнему просто разбрасывает ссылки на глобальный репозиторий экземпляров по всему вашему коду? Код, который будет вызывать,getInstance
должен иметь экземпляры, введенные в него клиентским кодом, и поэтому не должен вызыватьgetInstance
в первую очередь.Синглтоны очень мало, если не сказать «нет», используются в PHP.
В языках, где объекты находятся в общей памяти, синглтоны могут использоваться для снижения использования памяти. Вместо создания двух объектов вы ссылаетесь на существующий экземпляр из глобальной общей памяти приложения. В PHP такой памяти приложений нет. Синглтон, созданный в одном запросе, живет именно для этого запроса. Синглтон, созданный в другом запросе, выполненном в то же время, по-прежнему является совершенно другим экземпляром. Таким образом, одна из двух основных целей синглтона здесь не применима.
Кроме того, многие объекты, которые могут концептуально существовать только один раз в вашем приложении, не обязательно требуют языкового механизма для обеспечения этого. Если вам нужен только один экземпляр, не создавайте другой . Только тогда, когда у вас может не быть другого экземпляра, например, когда котята умирают, когда вы создаете второй экземпляр, у вас может быть допустимый вариант использования для синглтона.
Другой целью было бы иметь глобальную точку доступа к экземпляру в рамках того же запроса. Хотя это может показаться желательным, на самом деле это не так, потому что это создает связь с глобальной областью (как любые глобальные объекты и статика). Это усложняет модульное тестирование и делает ваше приложение менее удобным в обслуживании. Есть способы смягчить это, но в целом, если вам нужно иметь один и тот же экземпляр во многих классах, используйте внедрение зависимостей .
См. Мои слайды о синглтонах в PHP - почему они плохи и как вы можете удалить их из своих приложений для получения дополнительной информации.
Даже Эрих Гамма , один из изобретателей паттерна Синглтон, в наши дни сомневается в этом паттерне:
дальнейшее чтение
Если после вышесказанного вам все еще нужна помощь в принятии решения:
источник
Кому нужны синглтоны в PHP?
Обратите внимание, что почти все возражения против синглтонов исходят из технических точек зрения, но они также ОЧЕНЬ ограничены по своему объему. Специально для PHP. Сначала я перечислю некоторые причины использования синглтонов, а затем проанализирую возражения против использования синглтонов. Во-первых, люди, которым они нужны:
- Людям, которые пишут большой фреймворк / кодовую базу, которая будет использоваться во многих различных средах, придется работать с ранее существовавшими, разными фреймворками / кодовыми базами, с необходимостью реализации множества различных, изменяющихся, даже причудливых запросов от клиентов / боссов. / менеджмент / руководители подразделений делают.
Видите ли, шаблон singleton самодостаточен. Когда это будет сделано, одноэлементный класс будет жестким для любого кода, в который вы его включаете, и действует точно так же, как вы создавали его методы и переменные. И это всегда один и тот же объект в данном запросе. Поскольку он не может быть создан дважды, чтобы быть двумя разными объектами, вы знаете, что такое одноэлементный объект в любой заданной точке кода - даже если одноэлементный объект вставлен в две, три разных, старые или даже спагетти-кодовые базы. Следовательно, это упрощает задачу разработки - даже если над этим проектом работает много людей, когда вы видите, что синглтон инициализируется в одной точке в любой данной кодовой базе, вы знаете, что это такое, что он делает, как он делает, и состояние, в котором он находится. Если бы это был традиционный класс, вам нужно было бы отслеживать, где был впервые создан этот объект, какие методы были вызваны в нем до этого момента в коде и его конкретное состояние. Но поместите туда синглтон, и если вы отбросили правильные методы отладки, информации и отслеживания в синглтон во время его кодирования, вы точно знаете, что это такое. Таким образом, это облегчает людям, которым приходится работать с разными кодовыми базами, с необходимостью интеграции кода, которая была сделана ранее с использованием разных философий или сделана людьми, с которыми вы не контактируете. (то есть поставщик-проект-компания-чего там больше нет, поддержки нет). это облегчает работу людям, которым приходится работать с разными базами кода, с необходимостью интеграции кода, которая была сделана ранее с использованием разных философий или сделана людьми, с которыми вы не контактируете. (то есть поставщик-проект-компания-чего там больше нет, никакой поддержки нет). это облегчает работу людям, которым приходится работать с разными базами кода, с необходимостью интеграции кода, которая была сделана ранее с использованием разных философий или сделана людьми, с которыми вы не контактируете. (то есть поставщик-проект-компания-чего там больше нет, никакой поддержки нет).
- Люди, которым необходимо работать со сторонними API , сервисами и веб-сайтами.
Если вы присмотритесь, это не слишком отличается от предыдущего случая - сторонние API, службы, веб-сайты похожи на внешние изолированные кодовые базы, над которыми у вас нет контроля. Все может случиться. Таким образом, с помощью одноэлементного сеанса / пользовательского класса вы можете управлять ЛЮБОЙ реализацией сеанса / авторизации от сторонних поставщиков, таких как OpenID , Facebook , Twitter и многих других, и вы можете делать это ВСЕ одновременно из ОДНОГО одноэлементного объекта - который легко доступен в известном состоянии в любой момент любого кода, в который вы его вставляете. Вы даже можете создать несколько сеансов для нескольких различных сторонних API / сервисов для одного и того же пользователя на вашем собственном веб-сайте / в приложении и делать с ними все, что хотите.
Конечно, все это также может быть согласовано с традиционными методами с использованием обычных классов и объектов - уловка здесь в том, что синглтон более аккуратный, аккуратный и, следовательно, из-за этого легче управлять / тестировать по сравнению с традиционным использованием класса / объекта в таких ситуациях.
- Люди, которым нужно заниматься быстрым развитием
Поведение синглтонов, подобное глобальному, упрощает создание любого типа кода с помощью фреймворка, который имеет набор синглтонов для построения, потому что, как только вы хорошо сконструируете свои синглтон-классы, установленные, зрелые и установленные методы будут легко доступны и можно использовать везде, в любое время и единообразно. Требуется время, чтобы ваши классы стали более зрелыми, но после этого они станут твердыми, последовательными и полезными. У вас может быть столько методов в синглтоне, которые делают все, что вы хотите, и, хотя это может увеличить объем памяти объекта, он дает гораздо больше экономии времени, необходимого для быстрой разработки - метод, который вы не используете в одном конкретном экземпляре приложение может использоваться в другом интегрированном приложении, и вы можете просто добавить новую функцию, которую запрашивает клиент / начальник / менеджер проекта, всего за несколько модификаций.
Вы уловили идею. Теперь перейдем к возражениям против одиночек и нечестивому крестовому походу против чего-то полезного :
- Главное возражение состоит в том, что это затрудняет тестирование.
И действительно, до некоторой степени это так, даже если это можно легко смягчить, приняв надлежащие меры предосторожности и закодировав процедуры отладки в свои синглтоны С осознанием того, что вы будете отлаживать синглтон. Но видите ли, это не слишком отличается от ЛЮБОЙ другой философии / метода / шаблона кодирования, которые существуют - просто синглтоны относительно новы и не получили широкого распространения, поэтому текущие методы тестирования оказываются с ними сравнительно несовместимыми. Но это не отличается ни от одного аспекта языков программирования - разные стили требуют разных подходов.
Одно это возражение не соответствует действительности, поскольку оно игнорирует тот факт, что приложения разрабатываются не для «тестирования», и тестирование - не единственный этап / процесс, который входит в разработку приложения. Приложения разработаны для производственного использования. И, как я объяснил в разделе «Кому нужны синглтоны», синглтоны могут заключить ОТЛИЧНУЮ сделку из-за сложности необходимости заставить код работать ВНУТРИ и ВНУТРИ многих различных баз кода / приложений / сторонних сервисов. Время, которое может быть потеряно при тестировании, - это время, потраченное на разработку и развертывание. Это особенно полезно в эпоху сторонней аутентификации / приложений / интеграции - Facebook, Twitter, OpenID и многих других, и неизвестно, что будет дальше.
Хотя это и понятно - программисты работают в самых разных условиях в зависимости от карьеры. И для людей, которые работают в относительно больших компаниях с определенными отделами, занимающимися различным, определенным программным обеспечением / приложениями в удобной манере и без неминуемой гибели сокращения бюджета / увольнений и связанной с этим необходимости делать МНОГО вещей с большим количеством разных вещей в дешевый / быстрый / надежный способ, синглтоны могут показаться не столь необходимыми. И это может даже быть помехой / помехой тому, что у них УЖЕ есть.
Но для тех, кому нужно работать в грязных окопах «гибкой» разработки и выполнять множество различных запросов (иногда необоснованных) от своего клиента / менеджера / проекта, синглтоны - это спасительная благодать по причинам, объясненным ранее.
- Еще одно возражение заключается в том, что объем памяти у него выше.
Поскольку для каждого запроса от каждого клиента будет существовать новый синглтон, это МОЖЕТ быть возражением для PHP. Из-за плохо сконструированных и используемых синглтонов объем памяти приложения может быть выше, если приложение обслуживает много пользователей в любой момент.
Хотя это справедливо для ЛЮБОГО подхода, который вы можете использовать при кодировании. Следует задать следующие вопросы: являются ли методы и данные, которые хранятся и обрабатываются этими синглтонами, ненужными? Ибо, если они НЕОБХОДИМЫ для многих запросов, которые получает приложение, то даже если вы не используете синглтоны, эти методы и данные БУДУТ присутствовать в вашем приложении в той или иной форме через код. Таким образом, все становится вопросом о том, сколько памяти вы будете экономить, когда вы инициализируете традиционный объект класса 1/3 в обработке кода и уничтожаете его на 3/4 в нем.
Видите ли, если поставить такой вопрос, вопрос становится совершенно неактуальным - в вашем коде не должно быть ненужных методов, данных, содержащихся в объектах, в любом случае - независимо от того, используете вы синглтоны или нет. Итак, это возражение против синглтонов становится действительно забавным в том смысле, что оно ПРЕДПОЛАГАЕТ, что будут ненужные методы, данные в объектах, созданных из классов, которые вы используете.
- Некоторые недействительные возражения, такие как «делает невозможным / сложным поддержание нескольких подключений к базе данных»
Я даже не могу понять это возражение, когда всем нужно поддерживать несколько подключений к базе данных, несколько вариантов выбора базы данных, несколько запросов к базе данных, несколько наборов результатов в данном синглтоне, просто сохраняя их в переменных / массивах в синглтоне, пока они нужны. Это может быть так же просто, как хранить их в массивах, хотя вы можете изобрести любой метод, который хотите использовать для этого. Но давайте рассмотрим простейший случай, использование переменных и массивов в данном синглтоне:
Представьте, что ниже находится внутри синглтона данной базы данных:
$ this -> соединения = массив (); (неправильный синтаксис, я просто набрал его вот так, чтобы дать вам представление - правильное объявление переменной - public $ connections = array (); естественно, используется $ this-> connections ['connectionkey'])
Таким образом вы можете настроить и поддерживать несколько подключений в любой момент времени в массиве. То же самое касается запросов, наборов результатов и так далее.
$ this -> query (QUERYSTRING, 'queryname', $ this-> connections ['specificulrconnection']);
Который может просто выполнить запрос к выбранной базе данных с выбранным соединением и просто сохранить в вашем
$ this -> результаты
массив с ключом queryname. Конечно, для этого вам потребуется закодировать свой метод запроса, что сделать тривиально.
Это позволяет поддерживать практически бесконечное количество (в той мере, в которой, конечно, позволяют ограничения ресурсов) различных соединений с базой данных и наборов результатов, сколько вам нужно. И они доступны для ЛЮБОГО фрагмента кода в любой заданной точке любой данной кодовой базы, в которой был создан этот одноэлементный класс.
КОНЕЧНО, вам, естественно, потребуется освободить наборы результатов и соединения, когда они не нужны, но это само собой разумеется, и это не относится к синглтонам или любому другому методу / стилю / концепции кодирования.
На этом этапе вы можете увидеть, как можно поддерживать несколько подключений / состояний к сторонним приложениям или службам в одном синглтоне. Не так уж и иначе.
Короче говоря, в конце концов, одноэлементные шаблоны - это просто еще один метод / стиль / философия для программирования, и они так же полезны, как и ЛЮБЫЕ другие, когда они используются в правильном месте и правильным образом. Что ни от чего не отличается.
Вы заметите, что в большинстве статей, в которых рассматриваются синглтоны, вы также увидите ссылки на то, что «глобальные переменные» являются «злыми».
Посмотрим правде в глаза - все, что не используется должным образом, неправильно, неправильно, ЯВЛЯЕТСЯ злом. Это не ограничивается каким-либо языком, любой концепцией кодирования, любым методом. Всякий раз, когда вы видите, что кто-то делает общие заявления вроде «Х - зло», бегите от этой статьи. Очень высоки шансы, что это продукт ограниченной точки зрения - даже если точка зрения является результатом многолетнего опыта в чем-то конкретном, - что, как правило, в конечном итоге является результатом слишком много работы в определенном стиле / методе - типичный интеллектуальный консерватизм.
Для этого можно привести бесконечное количество примеров, начиная от «глобальные объекты - зло» до «iframe - это зло». Примерно 10 лет назад даже предложение использовать iframe в любом приложении было ересью. Затем идет Facebook, везде фреймы, и посмотрите, что произошло - фреймы больше не такие уж злые.
Есть еще люди, которые упорно настаивают на том, что они являются «злом», - а иногда и по уважительной причине тоже - но, как вы можете видеть, есть необходимость, плавающие фреймы удовлетворить эту потребность и хорошо работать, и поэтому весь мир просто двигается по.
Главный актив программиста / кодировщика / программиста - это свободный, открытый и гибкий ум.
источник
Многие считают синглтоны антипаттернами, поскольку на самом деле они просто прославленные глобальные переменные. На практике существует относительно небольшое число сценариев , в которых это необходимо для класса , чтобы иметь только один экземпляр; как правило , это только , что один экземпляр достаточно , в этом случае его реализация , как одноточечная совершенно ненужный.
Чтобы ответить на вопрос, вы правы, что синглтоны здесь излишни. Подойдет простая переменная или функция. Однако лучшим (более надежным) подходом было бы использование внедрения зависимостей, чтобы полностью избавиться от необходимости в глобальных переменных.
источник
В вашем примере вы имеете дело с одним фрагментом, казалось бы, неизменной информации. В этом примере синглтон был бы излишним, и просто использование статической функции в классе подойдет.
Еще мысли: у вас может быть случай применения шаблонов ради шаблонов, и ваша интуиция говорит вам «нет, вам не обязательно» по причинам, которые вы указали.
НО: Мы понятия не имеем о размере и масштабах вашего проекта. Если это простой код, возможно, выбросьте его, вряд ли его нужно будет менять, тогда да, используйте статические члены. Но если вы думаете, что ваш проект, возможно, потребуется масштабировать или подготовить для обслуживания кодирования в будущем, то да, вы можете использовать шаблон Singleton.
источник
Во-первых, я просто хочу сказать, что я не нахожу особого применения паттерну Синглтон. Зачем нужно держать один объект во всем приложении? Что, если я хочу подключиться к другому серверу баз данных, особенно для баз данных? Мне каждый раз приходится отключаться и снова подключаться ...? Тем не мение...
У использования глобальных переменных в приложении есть несколько недостатков (что и делает традиционное использование шаблона Singleton):
Использование статических классов вместо экземпляра синглтона также имеет некоторые из тех же недостатков, потому что самая большая проблема синглтона - это статический
getInstance
метод.Вы можете ограничить количество экземпляров класса, не используя традиционный
getInstance
метод:class Single { static private $_instance = false; public function __construct() { if (self::$_instance) throw new RuntimeException('An instance of '.__CLASS__.' already exists'); self::$_instance = true; } private function __clone() { throw new RuntimeException('Cannot clone a singleton class'); } public function __destruct() { self::$_instance = false; } } $a = new Single; $b = new Single; // error $b = clone($a); // error unset($a); $b = new Single; // works
Это поможет по первым пунктам, упомянутым выше: модульное тестирование и внедрение зависимостей; при этом убедитесь, что в вашем приложении существует единственный экземпляр класса. Например, вы можете просто передать полученный объект вашим моделям (шаблон MVC) для использования.
источник
Просто подумайте, чем ваше решение отличается от того, что представлено в документации PHP. На самом деле, есть только одна «небольшая» разница: ваше решение обеспечивает абонент геттера с
PDO
экземпляром, в то время как один в документации обеспечивает звонящие изDatabase::singleton
сDatabase
экземпляром (они затем используют сорбент на том , что , чтобы получитьPDO
экземпляр).Итак, к какому выводу мы пришли?
Database
экземпляр.Database
Класс может выставить (на самом деле, он должен выставить , если вы собираетесь на все эти проблемы) интерфейс богаче или более высокого уровня , чемPDO
объект он заворачивает.PDO
, то две реализации эквивалентны. Нет никакой пользы от выполнения ручного внедрения.С практической точки зрения синглтон - довольно противоречивая модель. Это в основном потому, что:
Итак, в качестве окончательного вывода: ваш синглтон в порядке. В большинстве случаев тоже нормально не использовать синглтон.
источник
Ваша интерпретация верна. Синглтоны имеют свое место, но ими злоупотребляют. Часто доступа к статическим функциям-членам бывает достаточно (особенно, когда вам не нужно каким-либо образом контролировать время построения). Более того, вы можете просто поместить несколько бесплатных функций и переменных в пространство имен.
источник
При программировании нет «правильного» и «неправильного»; есть «хорошая практика» и «плохая практика».
Синглтоны обычно создаются как класс для последующего повторного использования. Они должны быть созданы таким образом, чтобы программист случайно не создал два экземпляра во время пьяного кодирования в полночь.
Если у вас есть простой маленький класс, который не следует создавать более одного раза, вам не нужно делать его синглтоном. Если да, то это просто подстраховка.
иметь глобальные объекты - не всегда плохая практика. Если вы знаете, что собираетесь использовать его глобально / везде / все время, это может быть одним из немногих исключений. Однако глобальные переменные обычно считаются «плохой практикой» так же,
goto
как и плохой практикой.источник
Я вообще не вижу в этом смысла. Если вы реализовали класс таким образом, что строка подключения принималась в качестве параметра конструктора и поддерживала список объектов PDO (по одному для каждой уникальной строки подключения), тогда, возможно, была бы некоторая выгода, но реализация синглтона в этот случай кажется бессмысленным занятием.
источник
Насколько я понимаю, вы ничего не упускаете. Пример довольно ошибочный. Было бы иначе, если бы одноэлементный класс имел некоторые нестатические переменные экземпляра.
источник