ООП Singleton или глобальная переменная

Timol

Новичок
Провожу рефакторинг сайта, где использовались глобальные переменные. Теперь, для хранения настроек используется объект Config (Singleton). Вызов происходит примерно так:
PHP:
<?php
use ...\Config;

...
$Config = Config::getInstance();
$name = $Config->getConfig('name');
...
Глобальные переменные распределены по всем файлам проекта, например поиск по одной $host выдал около 50 файлов. Чтобы не переписывать вообще все с нуля я вижу 2 варианта: продолжить использовать глобальные переменные конфигурации или в каждом файле где используются переменные конфигурации подключить класс Config (use ...\Config), инициализировать его ($Config = Config::getInstance()) и доставать необходимые переменные (getConfig('name')).

Не сильно ли замедлит/нагрузит сервер второй вариант? Вопрос возник в связи с тем, что я не совсем понимаю механизм автоподключения классов. Если я использовал конфиг в файле index.php (use ...\Config), потом через require было подключено 20 файлов, в 10 из которых используется (use ...\Config), файл с классом Config читается один раз или 11?
 
Последнее редактирование:

A1x

Новичок
конечно файл будет читаться один раз. Автолоад срабатывает только когда класс не определен

Вообще если заинклудить два раза файл с одним и тем же классом будет Fatal error - Cannot redeclare class
 

WMix

герр M:)ller
Партнер клуба
PHP:
$name = Config::getInstance()->getConfig('name')
ни чем не лучше
PHP:
global $name
 

Timol

Новичок
ни чем не лучше
В глобальных переменных есть одна проблема: "по дороге" её можно случайно чем-нибудь переписать, и потом тяжело найти, где кроется проблема, особенно если тот же $name перезаписывается только по определенному условию, т.е. иногда.
 

Фанат

oncle terrible
Команда форума
Вот кстати все пугают, но я ни разу с таким не сталкивался.
А, скажем, случайно закрыть соединение без проблем можно и с синглетоном.
 

WMix

герр M:)ller
Партнер клуба
В глобальных переменных есть одна проблема: "по дороге" её можно случайно чем-нибудь переписать
@Timol, если у тебя в этом проблема, то да, ее победил, можно с таким же успехом define('NAME','blabla'); написать, и ни global ни Config::getInstance()->getConfig('name') не повторять
 

Timol

Новичок
Вот кстати все пугают, но я ни разу с таким не сталкивался.
А, скажем, случайно закрыть соединение без проблем можно и с синглетоном.
С перезаписью глобальной переменной столкнулся один раз, зато запомнил на долго. А про "закрыть соединение" не совсем понятно, просьба описать вашу мысль поподробнее.
@Timol, если у тебя в этом проблема, то да, ее победил, можно с таким же успехом define('NAME','blabla'); написать, и ни global ни Config::getInstance()->getConfig('name') не повторять
Не совсем верно: define('NAME','blabla'); будет доступно всегда и везде. А у меня конфигурации распределены по нескольким классам (глобальный, для каждого модуля, и т.п.), и читается только там, где они нужны. Например, зачем нужна константа SHOP_NAME если модуль интернет-магазина не запущен, а пользователь находится в модуле "Контакты"? А если таки в контактах нужно будет посмотреть SHOP_NAME - инициализируется нужный одиночка. Конечно, видимая польза от такого распределения - большой объем данных. Хотя, если использовать сторонние скрипты, то define('NAME','blabla'); может быть уже использована, и случится страшный ERROR! :) Поэтому я пока-что вижу больше плюсов в использовании Singleton, чем глобальных переменных или констант.
use ничего не подключает, просто задает алиас. Между use \Config; Config::... и \Config::... нет абсолютно никакой разницы.
Еврика - а таки да, спасибо!
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
@Timol, ви таки хочите минэ сказать (с), что если define('NAME','blabla'); может вызвать коллизию имени константы с "страшной" ошибкой, то в случае с синглтоном это будет не так страшно?
 

WMix

герр M:)ller
Партнер клуба
будет доступно всегда и везде.
Твоя конструкция также доступна везде, и так как ты не мог понять где используется global, также не знаешь где написано ::getInstance().
По той же логике как ты создаешь нужный "синглтон" можешь require необходимого файла с "defines". Ну да в общем, настройки совершенно не важная часть, интереснее иметь готовый обьект, который напичкан заренее конфигурацией, который решит нашу проблему считывания/записывания
 

Timol

Новичок
@Timol, ви таки хочите минэ сказать (с), что если define('NAME','blabla'); может вызвать коллизию имени константы с "страшной" ошибкой, то в случае с синглтоном это будет не так страшно?
Синглтон подключается через USE в верху файла, поэтому подключить два класса с одним названием намного сложнее, ибо видно все вверху файла, а use, в отличие от define распространяется только на тот файл, где используется. Поэтому, ответ - да.

Ну, кто первый скажет про dependency injection? :)
При разработке с нуля - конечно да, но при рефакторинге - нет, тут нужен простой надежный доступ к конфигурации из мешанины логики и представления.


Твоя конструкция также доступна везде, и так как ты не мог понять где используется global, также не знаешь где написано ::getInstance().
По той же логике как ты создаешь нужный "синглтон" можешь require необходимого файла с "defines". Ну да в общем, настройки совершенно не важная часть, интереснее иметь готовый обьект, который напичкан заранее конфигурацией, который решит нашу проблему считывания/записывания
Ну ты и сравнил... require необходимого файла с "defines" вызовет error, если константа уже существовала ранее, а use ...\Config + $Config = Config::getInstance() полностью лишен такого недостатка, даже если ранее $Config был совем другим объектом. Согласен с тобой только на счет того, что интереснее иметь готовый объект, но как я писал выше, в случае рефакторинга существующего приложения, это слишком затратно.
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
@Timol, правильный ответ - нет. Разжевать? Очень просто, константа у тебя вызовет ошибку при попытке ее переопределить, а вот если ты в синглтоне в сеттере просто перетираешь переменную внутри контейнера данных, ты получишь "счастливой отладки". Надо думать и потом делать, аккуратно, вот о чем была моя мысль.
 

Timol

Новичок
Спасибо, но к сожалению, разжовано совсем не то, теперь пожую я. Require_once не спасет от того, что одноименная константа используется в подключаемом файле сторонней библиотеки.

@Timol...вот о чем была моя мысль
Ок, теперь твоя мысль становится понятна, так бы и сразу, я мысли читать на расстоянии не научился. Спасибо, учту.

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

WMix

герр M:)ller
Партнер клуба
Нет, о константах зашла речь, потому как ты не понимаешь что при подключении класса или константы проблема таже, ты также не можешь заинклудить 2 раза класс, то что у тебя автолоадер, ничего не решает, под капотом require.

А намекаем тебе на di, на то что замена globаl на статический вызов, основной проблемы не решает. Но кажись ты не понял ни первого ни второго..
 

fixxxer

К.О.
Партнер клуба
А я, кажется, догадался, чего он хочет!

PHP:
use FooConfig as Config;

class Foo {
    public function doSomething() {
        $someConfigValue = Config::get('something');
    }
}
PHP:
use BarConfig as Config;

class Bar {
    public function doSomethingElse() {
        $someOtherConfigValue = Config::get('something_else');
    }
}
 
Сверху