Пользователь
192,0
рейтинг
10 марта 2013 в 03:01

Разработка → SimplePHPEasyPlus: Складываем числа на PHP

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

Библиотека годится для применения с продакшене. Наслаждайтесь!
Влад @ValdikSS
карма
620,0
рейтинг 192,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (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(); — свой фреймворк.
  • +12
    • –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();
            
            • +1
              Да у вас же Parse error at line FIVE!
              • 0
                И at line TEN!
  • +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
    Комментарий к методу не соответствует тому, что находится в методе
    • +1
      Сделайте пулл-реквест :)
  • 0
    А ограничения по размеру и точности чисел есть?
    • 0
      Родные из PHP
      $numbers = array($numberOne->getValue(), $numberTwo->getValue());
      $result = new $resultClass(array_sum($numbers));
      
  • 0
    Ничего себе приход у автора был! :)

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