<?php
// Класс разруливания тарифов
// 1. Базовый тарифный план, определяет поведение сервиса по умолчанию
// 2. Тарифные модификаторы вносят изменения в базовый план
// 3. Каждая опция может опеделить свою зависимость от другой(их) опции(й) предустановленным или кастомным колбеком
// 4. Конечные значения опции не где не хранятся они высчитываются при каждом обращении к ним
class Option {
public $alias;
public $value;
public function __construct($alias, $value) {
$this->alias = $alias;
$this->value = $value;
}
public function __invoke($plan) {
if (is_callable($this->value)) {
return call_user_func($this->value, $plan);
} else {
return $this->value;
}
}
}
class Plan implements \ArrayAccess, \Iterator {
public $options = [];
public $iterator;
public function __construct(...$plans) {
foreach ($plans as $plan) {
$this->merge($plan);
}
$this->iterator = new ArrayIterator($this->options);
}
public function addOption(Option $option) {
$this->options[$option->alias] = $option;
}
public function delOption($alias) {
if (isset($this->options[$alias])) {
unset($this->options[$alias]);
return true;
}
return false;
}
public function merge($plan) {
foreach ($plan as $alias => $value) {
if ($value instanceof Option) {
$this->addOption($value);
} else {
$this->addOption(new Option($alias, $value));
}
}
}
public function rewind() {
$this->iterator->rewind();
}
public function current() {
return $this->iterator->current();
}
public function key() {
return $this->iterator->key();
}
public function next() {
$this->iterator->next();
}
public function valid() {
return $this->iterator->valid();
}
public function offsetExists ($offset) {
return isset($this->options[$offset]);
}
public function offsetGet ($offset) {
return $this->$offset;
}
public function offsetSet ($offset, $value) {
$this->addOption(new Option($offset, $value));
}
public function offsetUnset ($offset) {
return $this->delOption($offset);
}
public function __get($name) {
if (!isset($this->options[$name])) return false;
return $this->options[$name]($this);
}
public function __set($offset, $value) {
$this->addOption(new Option($offset, $value));
}
}
// Пример
$basePlan = new Plan([
'sas' => false,
'messages' => 100,
'debug' => false,
'developer' => true
]);
//
$demoPlan = new Plan($basePlan, [
'widget' => function($plan) { return $plan->developer; },
'demo' => true,
'messages1' => function($plan) { return $plan->messages - 50; }
]);
echo $demoPlan->messages1;