SimplePHPEasyPlus: Складываем числа на PHP

    На ранних стадиях развития интернета, разработчикам приходилось использовать бедные, убогие языки программирования. Приходилось использовать только функции и операторы. Никаких объектов, никаких интерфейсов, никакого dependency injection!

    Скажем, чтобы выполнить простую операцию сложения, нашим отцам приходилось писать: 1+1. Да, серьезно.

    Но теперь-то у нас есть PHP 5.3 с отличной имплементацией ООП! Представляем библиотеку SimplePHPEasyPlus! SimplePHPEasyPlus позволит вам складывать два числа современным способом, с использованием ООП. Он быстрый, простой, гибкий и оттестированный. Чтобы добавить 1 к 1, нужно всего лишь выполнить следующее:

    use SimplePHPEasyPlus\Number\NumberCollection;
    use SimplePHPEasyPlus\Number\SimpleNumber;
    use SimplePHPEasyPlus\Number\CollectionItemNumberProxy;
    use SimplePHPEasyPlus\Parser\SimpleNumberStringParser;
    use SimplePHPEasyPlus\Iterator\CallbackIterator;
    use SimplePHPEasyPlus\Operator\AdditionOperator;
    use SimplePHPEasyPlus\Operation\ArithmeticOperation;
    use SimplePHPEasyPlus\Operation\OperationStream;
    use SimplePHPEasyPlus\Engine;
    use SimplePHPEasyPlus\Calcul\Calcul;
    use SimplePHPEasyPlus\Calcul\CalculRunner;
    
    
    $numberCollection = new NumberCollection();
    
    $numberParser = new SimpleNumberStringParser();
    
    $firstParsedNumber = $numberParser->parse('1');
    $firstNumber = new SimpleNumber($firstParsedNumber);
    $firstNumberProxy = new CollectionItemNumberProxy($firstNumber);
    
    $numberCollection->add($firstNumberProxy);
    
    $secondParsedNumber = $numberParser->parse('1');
    $secondNumber = new SimpleNumber($secondParsedNumber);
    $secondNumberProxy = new CollectionItemNumberProxy($secondNumber);
    
    $numberCollection->add($secondNumberProxy);
    
    $addition = new AdditionOperator('SimplePHPEasyPlus\Number\SimpleNumber');
    
    $operation = new ArithmeticOperation($addition);
    
    $engine = new Engine($operation);
    
    $calcul = new Calcul($engine, $numberCollection);
    
    $runner = new CalculRunner();
    
    $runner->run($calcul);
    
    $result = $calcul->getResult();
    $numericResult = $result->getValue(); // 2

    Библиотека годится для применения с продакшене. Наслаждайтесь!
    Метки:
    Поделиться публикацией
    Похожие публикации
    Комментарии 69
    • +45
      Годно. Шикарно. В самую центру.
      p.s.: Есть ощущение что ZF2 делался теми же разработчиками из тех же соображений.
      • +1
        В самую точку! Превосходно!
        • +21
          Боян же.
          • +21
            Ну так, zf еще год назад подобное умел.
            • +6
              Хоть и боян, но в проекте постоянно появляются новые лулзы!
              Вот, например, совсем свежий Pull Requеst, который добавляет Symfony 2 Bundle, чтобы можно было завернуть 90% кода в Sf2 DI контейнер: github.com/Herzult/SimplePHPEasyPlus/pull/15
            • +23
              Я надеюсь, unit тесты есть?
            • –5
              Есть же ресурсы, куда постят подобный код… И он получается, уж точно, не из-за ооп
              • +16
                А если серьезно, есть ли какие то критерии целесообразности использования технологий или подходов?

                Иногда мне кажется, что все вокруг бородатые суперпрограммисты, а я один пишу слишком простой код, без ООП, без сложных паттернов, фреймворков и прочих ORMов.

                Причем, мне мой код нравится — написал под наши задачи пару десятков основных функций, которые постоянно использую.

                Как понять, это я отстал от жизни, или это все остальные переусложняют?
                • +6
                  Думаю, остальные не переусложняют. Все эти паттерны, фреймворки и ООП придумали как-раз чтобы было легче работать с кодом и повторно его использовать. С большой кучей функций гораздо сложнее работать, чем с несколькими хорошо продуманными классами.

                  Если проект небольшой и с кодом будете работать только Вы, то пишите как нравится. В противном случае, стоит посмотреть в сторону более «сложных» подходов. В конечном счете, они сэкономят кучу времени и нервов.
                  • +6
                    А я считаю, что как раз таки оверинжининг встречается очень часто, и это большое зло. Он создает излишнюю неоправданную сложность. Что касается поста, то этот код спокойно можно переписать в структурном стиле, его суть не изменится.
                    • +21
                      Тем и отличается хороший программист от плохого, что он может найти баланс между оверинжинингом и недоинжинингом
                  • 0
                    Слишком простой код внезапно становится слишком сложным, когда проект растет. В случае с PHP это происходит вообще очень быстро. К чему вы упомянули ORM, не очень понятно — очень красивая и удобная штука. Чуть ограничены возможности, по сравнению с SQL, но, по моему опыту, скорость разработки увеличивается раз в 10. И где-то настолько же — понятность и читабельность кода.
                    • +1
                      Да и не факт, что ограничены. Надо сделать чистый SQL — берём NativeQuery в той же Docrine, и все дела :-)
                      • 0
                        Я о том, что есть задачи, где использование ORM не очень уместно (не писать же правда большую половину кода в виде raw-SQL запросов, вызываемых из ORM). Правда, стоит отметить, что такие задачи обычно не имеют отношения к вебу. )
                        • –6
                          Да и SQL зачастую тоже не очень уместно. Настройки программы, например. Практически во всех случаях достаточно какого-нибудь текстового файла key=value, парсящегося через fscanf(file, "%31s=%31s\n", key, value), а то и бинарника со структурой.
                          • +2
                            Эмм… Какое, блин, «зачастую»? :) Какое «практически во всех случаях»?

                            Каким чудом вы в тред с обсуждением ORM (и raw SQL) приплели настолько частный случай, как хранение настроек программы? o_O
                    • +3
                      Неприменительно к сложению 1+1: код в таком стиле используется при создании компиляторов или байт-кодовых машин. Прекрасный способ проверить компилятор на LLVM — поискать там символы /, *, %, и другие арифметические операции над числами. Если таковые есть, то скорее всего это ошибка (в свёртке констант такого тоже не должно быть, т. к. LLVM делает это сам). В итоге сложение выливается в лучшем случае в:
                      Value *one = ConstantFP::get(getGlobalContext(), APFloat(left));
                      Value *two = ConstantFP::get(getGlobalContext(), APFloat(right));
                      Value *result =  Builder.CreateFAdd(one, two, "addtmp");
                      

                      Но обычно используется не CreateFAdd, а AddFPMathAttributes(BinaryOperator::CreateFAdd... или CreateInsertNUWNSWBinOp(Instruction::Sub, ..., только вместо Instruction::Sub нужная инструкция на основе сопоставляющего массива, а не прописанная вручную. И это именно для облегчения восприятия. Теоретически, разработчики LLVM могли бы создать API, в котором есть класс BuilderValue, который инкапсулирует Value * и имеет полный набор перегруженных операторов С++. Только операций в LLVM намного больше, чем можно представить стандартными перегрузками, например, целочисленное сложение, сложение чисел с плавающей точкой, беззнаковое сложение и т. д.

                      Вот если бы в статье был оптимизирующий компилятор и вместо $runner = new CalculRunner(); что-то вроде $codeGen = new CodeGenerator();, тогда это был бы вполне нормальный пример для секции «Getting Started».
                      • +1
                        Хороший признак, что пора осваивать ООП — куча функций принимающих одним из параметров или возвращающих ассоциативный массив с одной или близкими структурами (в частности записи БД из fetch_assoc) или множество одинаковых параметров, функций с одинаковым префиксом/суффиксом (user_* или *_user). Если таких нет, то стоит присмотреться к коду — может в нем полно функций использующих глобалы и суперглобалы, может полно функций или скриптов на сотни и тысячи строк, может ещё какие признаки плохого запаха кода.

                        В принципе использование ООП, ORM и фреймворков не взаимосвязано. Начинать можно с чего-то одного — с ООП прежде всего. Как только начнете представлять записи в БД как объекты, у вас появится своя маленькая ускоспециализированная ORMка, как только начнете перетаскивать из проекта в проект код типа ($app = new Applicaction)->run(); — свой фреймворк.
                        • –9
                          Было бы забавно, если бы не так печально. В q&a уже в советах предлагают $.trim(text) вместо text.trim()
                          • +29
                            И правильно делают!
                            jQuery использует String.trim() если его поддерживает движок javascript.
                            Если же конечный пользователь использует какой-нибудь Internet Exporer 8 то будет применена регулярка.
                        • +36
                          Ого java программа на PHP!
                          • +17
                            Наверное, еще не хватает разухабистого xml-конфига. )
                            • +9
                              Все настройки в MySQL.
                              • 0
                                С асинхронным подключением к удалённой базе и запросом.
                                • +1
                                  В MongoDB, конечно же.
                                  • +2
                                    А ещё с онлайн-IDE, ресурсы которого лежат на CDN.
                                • 0
                                  Можно еще на С++ написать, и потом прокинуть в PHP через exec :)

                                  #include <iostream>
                                  
                                  using namespace std::placeholders;
                                  
                                  template <typename ...T>
                                  	int plus(T &&...value) {
                                  		return std::bind(std::plus<int>(), _1, _2)(value...);
                                  	}
                                  ;
                                  
                                  int main() {
                                  	std::cout << plus(1, 1) << std::endl; // 2
                                  
                                  	return 0;
                                  }
                                  
                                  
                                • +13
                                  Some people see a problem and think «I know, I'll use Java!» Now they have a ProblemFactory. ©
                                • +1
                                  Нужно еще добавить фабрики фабрик.
                                  • +2
                                    Да действиетльно! что это такое? new SimpleNumberStringParser();? Как можно напрямую вызывать new?? А вдруг надо будет другой парсер подсовывать и т.п.?
                                • +2
                                  Собственно, отличный гиперболизированный пример к моей статье. Сколько таких лишних классов люди писали не потому, что тонко решили пошутить, как автор, а что считали себя умнее всех и что могут сделать супергибкую структуру.

                                  А потом, когда профайлер показывает 15000 вызовов методов в одном экшне, сидишь и офигеваешь. Или тратишь полчаса на изучение всей иерархии классов. Пипец
                                  • +6
                                    Будет ли добавлен во второй версии автолоадер?
                                    • +1
                                      composer чем не угодил? Вызов composer install генерирует файл vendor/autoload.php.
                                    • +3
                                      Можно ли прикрутить redis в роли кеша?
                                      • +4
                                        Зачем redis? Нужен универсальный интерфейс кеша.
                                      • +5
                                        Толку-то от него? Там все равно «1» 2 раза написано… Вот если бы ввести константу для каждого числа, вот это да:)
                                        • 0
                                          Для каждой цифры, а числа будут собирать соответствующие фабрики.
                                          • +1
                                            Вы гениальны!
                                            Что-то типа:

                                            $num[0] = new Sequence(ONE, ONE, ONE)->getValue(); //111
                                            $num[1] = new Sequence(ONE, TWO, THREE)->getValue(); //123

                                            [Ушел писать свою библиотеку]
                                            • 0
                                              $num->add(new Sequence(ONE, ONE, ONE)->getValue());
                                              • +2
                                                В PHP можно получить возможность autoload, если писать не ONE, а что-нибудь вида NumberFactory::ONE (да и вообще, глобальные константы это зло), поэтому пример будет немного другой:

                                                $num[0] = new Sequence(NumberFactory::ONE, NumberFactory::ONE, NumberFactory::ONE)->getValue(); //111
                                                $num[1] = new Sequence(NumberFactory::ONE, NumberFactory::TWO, NumberFactory::THREE)->getValue(); //123
                                                

                                                • +2
                                                  Название «Sequence» неудачное, слишком общее. Я бы переименовал в «FiniteNaturalDecimalNumberSequence», а классы вроде «NumberSequence» оставил глубоко в иерархии. То же касается NumberFactory — явно имеются в виду десятичные цифры. И что за безобразие, какие ещё $num[0]?! Родные похапэшные массивы в ООП коде, да ещё и без говорящих названий переменных?

                                                  $finiteNaturalDecimalNumberSequenceFactory = new FiniteNaturalDecimalNumberSequenceFactory();
                                                  $decimalNumberFactory = new DecimalNumberFactory();
                                                  $firstSummandNumber = $finiteNaturalDecimalNumberSequenceFactory->createNewSequence(
                                                      $decimalNumberFactory->loadNumberFromXmlConfig("ONE"),
                                                      $decimalNumberFactory->loadNumberFromXmlConfig("ONE")
                                                      $decimalNumberFactory->loadNumberFromXmlConfig("ONE")
                                                  )->getValue();
                                                  $secondSummandNumber = $finiteNaturalDecimalNumberSequenceFactory->createNewSequence(
                                                      $decimalNumberFactory->loadNumberFromXmlConfig("ONE"),
                                                      $decimalNumberFactory->loadNumberFromXmlConfig("TWO")
                                                      $decimalNumberFactory->loadNumberFromXmlConfig("THREE")
                                                  )->getValue();
                                                  
                                        • +2
                                          Листинг напомнил стектрейс Java + Spring AOP, верной дорогой идете товарищи :)
                                          • +14
                                            У вас есть hardcoded константы в коде, это плохая практика, их обязательно нужно вынести в конфиг в формате XML.
                                            • +1
                                              Итератор от sql-injection забыли защитить.
                                              • +1
                                                Еще нужно обязательно сделать SOAP-веб-сервис. XML/JSON — для нубов, они слишком простые.
                                                • 0
                                                  Прикольная штука, лично мне нравится
                                                  • –19
                                                    Прямо в стиле php: Длинно, нудно, глючно
                                                    • +1
                                                      Вообще, больше похоже на стиль java. По крайней мере, первые 2 слова.
                                                      • +1
                                                        Вы слишком долго пользовались Zend Framework и Symfony.
                                                      • 0
                                                        Упущен вопрос представления, не мешало бы создать еще шаблонизатор под эту библиотеку
                                                        • –1
                                                          Честно говоря, конечная реализация не впечатлила:

                                                          Скрытый текст
                                                          github.com/Herzult/SimplePHPEasyPlus/blob/master/src/SimplePHPEasyPlus/Operator/AdditionOperator.php

                                                          <?php
                                                          
                                                          namespace SimplePHPEasyPlus\Operator;
                                                          use SimplePHPEasyPlus\Number\NumberInterface;
                                                          
                                                          class AdditionOperator implements OperatorInterface
                                                          {
                                                              protected $resultClass;
                                                          
                                                              public function __construct($resultClass)
                                                              {
                                                                  $this->resultClass = $resultClass;
                                                              }
                                                          
                                                              public function process(NumberInterface $numberOne, NumberInterface $numberTwo)
                                                              {
                                                                  $resultClass = $this->resultClass;
                                                          
                                                                  $numbers = array($numberOne->getValue(), $numberTwo->getValue());
                                                                  $result = new $resultClass(array_sum($numbers));
                                                          
                                                                  return $result;
                                                              }
                                                          }
                                                          



                                                          Я надеялся увидеть, хотя бы, реализацию сложения столбиком или, например, какую-нибудь реализацию параллельного сложения (с использованием pcntl_fork и shm для синхронизации).
                                                          • +3
                                                            Так для того и ООП, чтобы вы могли переписать один класс как хотите и ничего в остальной программе не изменится :)
                                                          • +1
                                                            Апплодирую стоя=)
                                                            • 0
                                                              Было бы уместнее опубликовать это через три недели. ;-)
                                                              Кстати, скобки при создании экземляра объекта без аргументов необязательны.
                                                              • +1
                                                                use SimplePHPEasyPlus\Iterator\CallbackIterator;

                                                                Похоже лишний, либо разработчики фреймворка не до конца продумали )
                                                                • +11
                                                                  Задумка хорошая, но до конца не добита — прочитав код примера, я всё ещё могу понять, что там делается. В идеале хотелось бы этого избежать.
                                                                  • 0
                                                                    github.com/Herzult/SimplePHPEasyPlus/blob/master/tests/Functional/AdditionTest.php

                                                                    stupidcodereview mode on
                                                                    Комментарий к методу не соответствует тому, что находится в методе
                                                                  • 0
                                                                    А ограничения по размеру и точности чисел есть?
                                                                    • 0
                                                                      Родные из PHP
                                                                      $numbers = array($numberOne->getValue(), $numberTwo->getValue());
                                                                      $result = new $resultClass(array_sum($numbers));
                                                                      
                                                                    • 0
                                                                      Ничего себе приход у автора был! :)

                                                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.