Наверное, названия вопроса трудно что-то понять, попытаюсь объяснить, чтобы было понятно.
Стояла задача сделать проверку на вхождение текущего IP в список исключений. Это делается просто вызовов статического метода (IpAddressExclusion::isExcluded), который пробегается по свойству-массиву IP (задан жестко в классе, плохо, но сейчас не в этом суть), и смотрит есть ли текущий IP юзера в этом массиве. Но проблема в том, что этот вызов метода вызывается на странице несколько раз и сейчас выходит так, что каждый раз делается такая же самая проверка, пусть даже она уже проводилась, а это ведь плохо?
Например, есть вызов этого метода в шапке сайта, потом в сайдбаре, а затем в футере - соответственно, если проверка выполнилась в шапке, то нет смысла делать её в сайдбаре и футере, а нужно просто вернуть сохраненное состояние (то есть лог. значение, которое сохранилось в свойстве при первой проверке в шапке)? Если так, то как это грамотно сделать? Правильно ли я понимаю, здесь нужен синглтон? Т.е. в методе isExcluded нужно сохранять состояние проверки и потом проверять если это свойство не null, то возвращать его? Но тогда получится что-то типа такой конструкции: IpAddressExclusion::getInstance()->isExcluded()? Это нормально, смущает что метод getInstance получается статическим, хотя не должен ведь?
Надеюсь понятно что я хочу, новичок ещё, но очень хочется сделать по-нормальному, поэтому всё так расписал :/
'a' и 'b' - будут иметь один и тот же объект.
---
Чтобы сохранялось свойство надо примерно такой код:
class C
{
private $p;
public function getProperty() {
if (is_null($this->p)) {
$this->p = ...
}
return $this->p;
}
}
---
Реализация синглтона в простеньком виде:
class C
{
private static $instance;
private function __constructor() {
// init
}
public static function getInstace() {
if (is_null($this->instance)) {
$this->instance = new self();
}
return $this->instance;
}
}
А что должно быть в конструкторе? Или он не отработает? В него нельзя поместить логику проверки?
Странно, почему-то всегда думал что getInstance должен быть обычным методом, хотя наверное из-за того, что встречаются разные варианты, то статический, то нет.
unfapable: не статический getInstance - уже не сигнлтон, т.к. вы должны изначально вызвать конструктор (а вызывать конструктор, а потом отдавать Instance как то глупо и неправильно). В конструкторе инициализация объекта. Это обычный конструктор, все как обычно (только вот вызывается он один раз).
Что-то у меня действительно всё плохо с ООП. В таком случае проверку на IP и вовсе можно вынести в конструктор, а далее просто обращаться к свойству состояния, да?
unfapable: в конструкторе инициализировать лучше то, что понадобиться в любом случае, а все остальное кешировать по мере надобности. LazyLoad с кешированием получается)
unfapable: вызывать то-что выше в коде нужно так: C::getInstace()->isExcluded("127.0.0.1")
Если вы хотите что-то ПОНЯТЬ - задавайте вопросы, если вам просто нужен код, то так и пишите, чтобы не париться с объяснениями!
Илья, спасибо, код необязательно было писать, мне непонятно было как лучше было реализовать. К примеру, зачем определять свойство allowIps внутри конструктора, ведь также можно это сделать непосредственно в классе, точнее можно было объявить сразу здесь:
private $allowIps = [
'127.0.0.0',
'0.0.0.0'
];
Также неясно зачем нужен синглтон, как альтернатива - сделать статическим метод isExcluded, и непосредственно к нему обращаться. Вот эти вопросы волнуют меня, но это уже от недостатка знаний/скллов/интеллекта и т.д.
unfapable: все что описано ниже это лично мое мнение, которому я следую в настоящее время:
1. Объявлять сразу нужно константы, все что не константы инициализируются либо к конструкторе, либо в отдельном методе - (если вы данные грузите к примеру из базы, то не получиться объявить сразу и смотрится лучше);
2. Синглтон гарантирует один единственный экземпляр/объект (если будет не синглтон, то в каждом следующем файле, переменная isExcluded заново бы инициализировать кеширующую переменную (если создавать новый объект, если сделать все статически, то конечно все проще: вместо $this - self ).
3. Вы знаете что такое синглтон - все впорядке со знаниями))))
---
Вот если честно не совсем догоняю разницу сигнлтона и статического класса, (если она конечно есть). А реализовать нужно так, как вам удобно, если нет других условий)
Вы вызываете статический метод класса, по этому синглтон тут неуместен, поскольку синглтон возвращает объект, а статический метод указывает на класс. Да и пробежаться по массиву и найти есть ли там IP не затратная операция. PHP достаточно шустро работает с массивами. По мне это оптимизация ради оптимизации.
upd:
class IpAddressExclusion
{
static private $instance;
private $cache;
private $excluded = [
'192.168.1.1',
'192.168.1.2',
'192.168.1.3',
];
private function __construct()
{
}
private function setCache($key, $value)
{
if (!isset($this->cache[$key])) {
$this->cache[$key] = $value;
}
}
private function getCache($key)
{
if ($this->hasCache($key)) {
return $this->cache[$key];
}
return null;
}
private function hasCache($key)
{
return isset($this->cache[$key]);
}
public function isExcluded($ip)
{
$search = array_search($ip, $this->excluded);
if ($search && $search !== 0) {
if ($this->hasCache($ip)) {
return $this->getCache($ip);
} else {
$this->setCache($ip, true);
}
return true;
}
return false;
}
public static function getInstance()
{
if (!self::$instance) {
self::$instance = new IpAddressExclusion();
}
return self::$instance;
}
}
Тогда использовать так:
if (IpAddressExclusion::getInstance()->isExcluded('192.168.1.1')) {
//Делам что то
}
Под сохранением свойства я имел в виду что-то типа кеширование, нежели оптимизацию. Хотя да, ваше замечание верно, не знаю, мне подумалось, что было бы хорошо, если только один раз делалась проверка.
Получается, мне тогда вообще не нужен синглтон, а просто нужен класс и статический метод проверки.
unfapable: Можно использовать разные решения, тут никто не скажет так делать надо а так не надо. Можно использовать статичный метод и статичный массив для хранения адресов. Можно использовать и синглтон с кэшированием. Пример в ответе выше.