БлогNot. PHP: простой класс-сумматор

PHP: простой класс-сумматор

Пример того, как обрабатывать методом класса любое количество аргументов (метод plus), различать аргументы-числа и строки (конструктор и тот же метод), выводить данные по формату, заданному свойством класса.

Проверено в XAMPP с PHP 7.3.3.

Хорошее задание по теме - "написать маленький класс, делающий что-нибудь полезное".

<?php
 class Summa { //Простой класс-сумматор
  private $sum,$cnt,$fmt="%.3F";
   //Формат - как у функции sprintf:
   //https://www.php.net/manual/ru/function.sprintf.php
  
  function __construct ($sum='') { 
   $this->sum = (is_numeric($sum) ? $sum : 0);
   $this->cnt = (is_numeric($sum) ? 1 : 0); 
  }
  
  function plus() { //Количество аргументов функции - любое
   $numargs = func_num_args(); 
   $arglist = func_get_args();
   for ($i=0; $i<$numargs; $i++) 
	if (is_numeric($arglist[$i])) {
	 $this->sum += $arglist[$i];
     $this->cnt ++;
    }
  }
  
  function summa() { return $this->sum; }
  
  function count() { return $this->cnt; }
  
  function average() { return $this->sum/$this->cnt; }
  
  function setFormat ($fmt) { $this->fmt = $fmt; }
  
  function format($s) { return sprintf ($this->fmt,$s); }
 } //end of class Summa
 
 //Проверка возможностей класса:
 $s = new Summa(); //Сумма и количество инициализируются нулями
 $s->setFormat ('%.2F');
 $s->plus(1,2,'test'); 
 $s->plus(3,4);
 echo 'Sum(s)='.$s->format($s->summa()).
    ', Avg(s)='.$s->format($s->average()).
    ', Cnt(s)='.$s->count(); //10.00, 2.50, 4
 $d = new Summa(0); //"0" посчитается как число!
 $d->plus(1);
 echo '<br>Avg(d)='.$d->format($d->average()); //0.500
?>

Приведём более современный пример небольшого класса, способного хранить числовые значения в контейнере $vals и вычислять их простые арифметические и статистические характеристики.

Начиная с PHP версии 5.6 в применении функций func_num_args и func_get_args, в общем, нет необходимости, так как теперь можно передавать массив аргументов с многоточием, как и сделано при вызове конструктора или метода add. В методе insert для сравнения оставлен вызов этих функций с целью проверки того, сколько аргументов передано и (при необходимости) выброса исключения.

В классе есть магический метод __toString, чтобы вернуть его строковое представление, например, для вывода оператором echo. Пример проверен в XAMPP с PHP 7.4.2.

<!DOCTYPE html>
<html lang="ru">
<head>
 <title>Series</title>
 <meta charset="utf-8">
</head><body>

<?php
 //Простой класс для статистической обработки чисел:
 class Series { 
  private $vals, //Массив чисел
          $fmt;  //Формат для вывода
  function __construct (...$vals) { //...$vals работает с версии PHP 5.6
   //Конструктор, в PHP бывает только один у класса
   $this->vals = [];
   $this->add ($vals);
   $this->setFormat(); 
  }
  function __destruct () { //Деструктор, реально память не освободит
   $this->vals = [];
   unset($this->vals);
  }
  function __unset($val) { //На всякий случай, т.к. применяем unset к приватным свойствам
   unset($val);
  }
  function __toString() { //"Магический метод" - вернуть строковое представление класса
   return implode(',',$this->vals);
  }
  function add(...$items) { //Добавить любое количество элементов в конец
   $this->vals = array_merge (array_slice($this->vals,0) , $this->get_array(...$items));
  }
  private function get_array(...$items) { //Сформировать числовой массив из своих аргументов
   $vals = [];
   foreach ($items as $item) {
    if (is_numeric($item)) $vals[] = $item;
    else if (is_array($item)) {
     foreach ($item as $subitem) {
      if (is_numeric($subitem)) $vals[] = $subitem;
     }
    } 
   }
   return $vals;
  }
  function insert ($num=0,...$vals) { //Вставить элемент(ы) в позицию $num
   $numargs = func_num_args(); //До PHP 5.6 - количество аргументов функции
   $arglist = func_get_args(); //До PHP 5.6 - список аргументов функции
   if ($numargs < 2 or !is_numeric($arglist[0])) 
    throw new Exception ('Передайте хотя бы 2 аргумента, первый из которых - число');
   $cnt = $this->cnt();
   if ($num < 0) $num = 0;
   else if ($num > $cnt) $num = $cnt;
   $this->vals = array_merge (
    array_slice($this->vals,0,$num), 
    $this->get_array(...$vals), 
    array_slice($this->vals,$num)
   );
  }
  function remove ($val,$all=false) { //Удалить элемент(ы) по значению, $all=true - все вхождения
   while (($key=array_search($val,$this->vals)) !== false) {
    unset($this->vals[$key]); 
    if (!$all) break;
   }
  }
  private function swap(&$left, &$right) {
   if ($left == $right) return;
   $tmp = $left; $left = $right; $right = $tmp;
  }
  function removeIndex ($n1,$n2=-1) { //Удалить элемент(ы) с номерами от $n1 до $n2 включительно
   if ($n2<0 or $n2==$n1) unset($this->vals[$n1]);
   else {
    if ($n1>$n2) $this->swap ($n1, $n2);
    if ($n1 < 0) $n1 = 0;
    if ($n2 > $this->cnt()-1) $n2 = $this->cnt()-1;
    array_splice($this->vals, $n1, $n2-$n1+1);
   }
   $this->vals = array_values($this->vals); //Переиндексировать!
  }
  function summa () { //Сумма
   return $this->format(array_sum($this->vals)); 
  }
  function cnt () { //Количество
   return count($this->vals); 
  } 
  function average () { //Арифметическое среднее
   $n = $this->cnt();
   return $n==0 ? false : 
    $this->format($this->summa($this->vals) / $n);
  }
  function max() { return max($this->vals); } //Максимум
  function min() { return min($this->vals); } //Минимум
  function sortAsc() { //Сортировка по возрастанию
   usort($this->vals,function($a,$b){ return ($a < $b ? -1 : 1); }); 
   } 
  function sortDesc() { //Сортировка по убыванию
   usort($this->vals,function($a,$b){ return ($a > $b ? -1 : 1); }); 
  } 
  function format ($s) { //Форматировать число
   return sprintf ($this->fmt,$s); 
  }
  function setFormat ($fmt = '%.2F') { 
   //Установить нужный формат чисел для вывода
   //См. https://www.php.net/manual/ru/function.sprintf
   $this->fmt = $fmt;
  }
 }
 
 //Пример работы класса:
 $s = new Series(1,2); //вызов конструктора
 $s->add(3,array(4,5)); //вызов метода
 echo '<p>После добавления: '.$s.'</p>'; //неявный вызов метода __toString
 $s->insert(0,6);
 $s->insert(1,7);
 $s->insert($s->cnt(),array(8,9),10);
 echo '<p>После вставки: '.$s.'</p>';
 $s->add(2,1);
 echo '<p>Добавлено ещё 2 элемента в конец: '.$s.'</p>';
 $s->remove(10);
 $s->remove(1,true);
 echo '<p>Удалено 3 элемента: '.$s.'</p>';
 $s->removeIndex(0);
 echo '<p>Удален элемент номер 0: '.$s.'</p>'; 
 $s->removeIndex(2,5);
 echo '<p>Удалены элементы с номерами от 2 до 5: '.$s.'</p>'; 
 echo '<p>Количество='.$s->cnt().'</p>';
 echo '<p>Сумма='.$s->summa().'</p>';
 echo '<p>Среднее='.$s->average().'</p>';
 echo '<p>Минимум='.$s->min().'</p>';
 echo '<p>Максимум='.$s->max().'</p>';
 $s->sortDesc();
 echo '<p>Отсортировано по убыванию: '.$s.'</p>';
 $s->sortAsc();
 echo '<p>Отсортировано по возрастанию: '.$s.'</p>';
 unset($s); //вызов деструктора
?>
</body></html>

После добавления: 1,2,3,4,5

После вставки: 6,7,1,2,3,4,5,8,9,10

Добавлено ещё 2 элемента в конец: 6,7,1,2,3,4,5,8,9,10,2,1

Удалено 3 элемента: 6,7,2,3,4,5,8,9,2

Удален элемент номер 0: 7,2,3,4,5,8,9,2

Удалены элементы с номерами от 2 до 5: 7,2,9,2

Количество=4

Сумма=20.00

Среднее=5.00

Минимум=2

Максимум=9

Отсортировано по убыванию: 9,7,2,2

Отсортировано по возрастанию: 2,2,7,9

теги: учебное программирование php

01.04.2019, 12:53; рейтинг: 478