<?php
header("Content-Type: text/plain");
mb_internal_encoding('utf-8');

//  ООП. Вектор и антикризичные меры

// Класс сотрудника
class Employee
{
    private $rank = 1;      // ранг
    private $chief = 0;     // статус руководителя
    private $profession;    // профессия
    private $salaryRate = 0;// индивидуальная ставка работника
    private $coffeeRate = 0;// индивидуальное потребление кофе  

    // Коофициенты зарплаты для ранга
    private $rankSalary = array(1 => 1,
        2 => 1.25,
        3 => 1.5);
    // Коофициенты зарплаты для начальников
    private $chiefSalary = array(0 => 1,
        1 => 1.5);
    // Коофициенты потребления кофе для начальников
    private $chiefCoffee = array(0 => 1,
        1 => 2);
    // Коофициенты продуктивности для начальников
    private $chiefProduct = array(0 => 1,
        1 => 0);

    public function __construct(Profession $profession, $rank, $chief)
        {
        // Присвоение профессии сотруднику
        $this->profession = $profession;
        // Присвоение ранга сотруднику
        $this->rank = $rank;
        // Присвоение статуса начальник
        $this->chief = $chief;
    }

    // Присвоение профессии сотруднику
    public function addProfession(Profession $profession)
    {
        $this->profession = $profession;
        // Сбрасываем ставку при смене профессии
        $this->salaryRate = 0;
        // Сбрасываем потребление кофе
        $this->coffeeRate = 0;
    }

    // Возвращает ранг сотрудника
    public function getRank()
    {
        return $this->rank;
    }

    // Присвоение ранга
    public function setRank($rank)
    {
        $this->rank = $rank;
    }

    // Изменение статуса начальника
    public function setСhief($chief)
    {
        $this->chief = $chief;
    }

    // Изменение ставки
    public function setSalaryRate($salary)
    {
        $this->salaryRate = $salary;
    }

    // Изменение кол-во выпиваемого кофе
    public function setCoffeeRate($coffee)
    {
        $this->coffeeRate = $coffee;
    }

    // Возвращаем название профессии сотрудника
    public function getProfession()
    {
        return $this->profession;
    }

    // Возвращаем статус шафа сотрудника
    public function getChief()
    {
        return $this->chief;
    }

    // Расчет зарплаты
    public function getSalary()
    {
        // Профессия
        $profession = $this->profession;
        // Ставка, берем из данного класса если поле переопределено, иначе берем из профессии
        if ($this->salaryRate != 0) {
            $salaryRate = $this->salaryRate;
        } else {
            $salaryRate = $profession->getSalaryRate();
        }        
        // Узнаем коэффициент согласно рангу сотрудника
        $salaryMultiplier = $this->rankSalary[$this->rank];
        // Узнаем коэффициент для начальника
        $chiefSalaryMultiplier = $this->chiefSalary[$this->chief];
        // Расчет зарплаты
        $salary = $salaryRate * $salaryMultiplier * $chiefSalaryMultiplier;

        return $salary;
    }

    // Расчет потребления кофе
    public function getCoffee()
    {
        // Профессия
        $profession = $this->profession;
        // Потребление  кофе
        // Берем из данного класса если поле переопределено, иначе берем из профессии
        if ($this->coffeeRate != 0) {
            $coffeeRate = $this->coffeeRate;
        } else {
            $coffeeRate = $profession->getCoffeeRate();
        }        
        // Вычисляем коэффициент для начальника
        $tmpchiefCoffee = $this->chiefCoffee[$this->chief];
        // Расчет потребления кофе
        $coffee = $coffeeRate * $tmpchiefCoffee;

        return $coffee;
    }

    // Расчет продуктивности
    public function getProduct()
    {
        // Профессия
        $profession = $this->profession;
        // Продуктивность по профессии
        $productRate = $profession->getProduct();
        // Вычисляем коэффициент для начальника
        $tmpchiefProduct = $this->chiefProduct[$this->chief];
        // Расчет продуктивности
        $product = $productRate * $tmpchiefProduct;

        return $product;
    }
    
    
}

// Абстрактный класс профессии
abstract class Profession
{
    // Возвращает имя
    public function getName()
    {
        return get_class($this);
    }
    
    abstract public function getSalaryRate();

    abstract public function getCoffeeRate();

    abstract public function getProduct();
}

// Класс менджер
class Manager extends Profession 
{ 
    public function getSalaryRate()
    {
        return 500;
    }

    public function getCoffeeRate()
    {
        return 20;
    }

    public function getProduct()
    {
        return 200;
    }
}

// Класс маркетолог
class Marketer extends Profession
{
    public function getSalaryRate()
    {
        return 400;
    }

    public function getCoffeeRate()
    {
        return 15;
    }
    public function getProduct()
    {
        return 150;
    }
}

// Класс инженер
class Engineer extends Profession
{
    public function getSalaryRate()
    {
        return 200;
    }

    public function getCoffeeRate()
    {
        return 5;
    }
    public function getProduct()
    {
        return 50;
    }
}

// Класс аналитик
class Analyst extends Profession
{
    public function getSalaryRate()
    {
        return 800;
    }

    public function getCoffeeRate()
    {
        return 50;
    }

    public function getProduct()
    {
        return 5;
    }
}

// Класс департамента
class Departament
{
    public $name = "";            // название
    private $employees = array(); // сотрудники

    public function __construct($name)
    {
        $this->name = $name;
    }

    // Клонирование департамента
    public function __clone()
    {
        $employeesClones = array(); // клоны работников

        foreach ($this->employees as $employee) {
            $employee = clone $employee;
            $departamentsClones[] = $employee;
        }
        // Заменяем массив работников массивом клонов
        $this->employees = $departamentsClones;
    }

    // Прием сотрудника на работу
    public function addEmployee(Employee $employee)
    {
        $this->employees[] = $employee;
    }

    // Расчет количества сотрудников по профессии, не указанный параметр возвращает общее кол-во
    public function countEmployees($profession = null)
    {
        $employeesNumber = 0; // число сотрудников

        // Если профессия не задана
        if (!$profession) {
            return count($this->employees);
        }

        // Если считаем сотрудников определенной профессии
        foreach ($this->employees as $employee) {

            // Если сотрудник не соответствует профессии
            if ($employee->getProfession()->getName() != $profession) {
                continue;
            }
            // Счетчик
            $employeesNumber++;
        }
        return $employeesNumber;
    }

    // Возвращаем сотрудников массивом
    public function getEmployees()
    {
        return $this->employees;
    }

    // Возвращает сотрудников заданной профессии массивом
    public function findEmployees($profession)
    {
        $employees = array(); // массив Сотрудников

        // Перебираем всех сотрудников
        foreach ($this->employees as $employee) {
            // Если название класса профессии сотрудника соответствует профессии
            if (get_class ($employee->getProfession()) == $profession) {                
                $employees[] = $employee;
            }
        }
        // Возвращаем Сотрудников
        return $employees;
        
    }
    
    // Возвращает шефа департамента
    public function getChief()
    {
        // Фильтруем работников по признаку шефства
        $chief = array_filter ($this->employees, function ($e) { return ($e->getChief()==1) ;});
        // Сбрасываем индексы массива
        $chief = array_values($chief);
        return $chief[0];
    }

    // Увольнение сотрудника
    public function dismissEmployee($employee)
    {
        $employeeKey = array_search($employee, $this->employees, TRUE);
        unset ($this->employees[$employeeKey]);
    }
    
    // Замена шефа департамента
    public function replaceChief(Employee $employee)
    {
        // Ищем переданного работника в данном департаменте
        $employeeKey = array_search($employee, $this->employees, TRUE);
        // Если в департаменте не существует переданного работника
        if ($employeeKey == null) {
            // Выкидываем исключение
            throw new Exception ("Переданный работник не найден");
        }
        
        // Возвращаем текущего шефа к обычной работе
        $chief = $this->getChief(); // метод поиска шефа
        $chief->setСhief(0);
        
        // Назначаем работника шефом
        $this->employees[$employeeKey]->setСhief(1);
    }

    // Расходы на зарплату
    public function getTotalCoffee()
    {
        $totalCoffee = 0;     // сумарное потребление кофе
        // Для каждого сотрудника
        foreach ($this->employees as $employee) {
            // Запрашиваем потребление кофе у сотрудника  и суммируем результат
            $totalCoffee += $employee->getCoffee();
        }
        return $totalCoffee;
    }

    // Рассход кофе

    public function getAverageCostPerProduct()
    {
        // Средняя стоимость 1 страницы = суммарная зарплата / сумарное количество страниц
        $avrCostPerProduct = $this->getTotalSalary() / $this->getTotalProduct();

        return $avrCostPerProduct;
    }

    // Суммарная производительность

    public function getTotalSalary()
    {
        $totalSalary = 0;     // сумарная зарплата
        // Для каждого сотрудника
        foreach ($this->employees as $employee) {
            // Запрашиваем зп у сотрудника и суммируем результат
            $totalSalary += $employee->getSalary();
        }
        return $totalSalary;
    }

    // Средний расход тугриков на одну страницу

    public function getTotalProduct()
    {
        $totalProduct = 0;     // сумарная продуктивность
        // Для каждого сотрудника
        foreach ($this->employees as $employee) {
            // Запрашиваем продуктивность у сотрудника и суммируем результат
            $totalProduct += $employee->getProduct();
        }
        return $totalProduct;
    }
}

// Класс компании
class Company
{
    public $name = ""; // название
    private $departaments = array(); // департаменты

    public function __construct($name)
    {
        $this->name = $name;
    }

    // Клонирование компании
    public function __clone()
    {
        $departamentsClones = array(); // клоны департаментов

        foreach ($this->departaments as $departament) {
            $departament = clone $departament;
            $departamentsClones[] = $departament;
        }
        // Заменяем массив департаментов массивом клонов
        $this->departaments = $departamentsClones;
    }

    // Создание департамента
    public function createDepartament($name)
    {
        $this->departaments[$name] = new Departament ($name);
    }
    
    // Возвращает все департаменты массивом
    public function getAllDepartments ()
    {
        return $this->departaments;
    }

    // Поиск департамента по названию,
    // если название не определено, возращает все департааменты
    public function findDepartamentByName($name = null)
    {
        $result = null; // ссылка на департамент или массив департаментов
        // Ищем департамент в массиве по названию
        if ($name) {
            $result = $this->departaments[$name];
        } else {
        // Возвращаем все департаменты массивом
            foreach ($this->departaments as $name => $departament) {
                $result[$name] = $departament;
            }
        }
        // Если ничего не нашли
        if ($result == null) {
            // Ничего не возвращам, выкидываем исключение
            throw new Exception ( "Департамент не найден" ) ;
        }
        return $result;
    }

    // Сумарное количество работников

    public function getAverageEmployees()
    {
        // Среднее количество работников = суммарное кол-во работников / кол-во департаментов
        $avrEmployees = $this->getTotalEmployees() / count($this->departaments);

        return $avrEmployees;
    }

    // Расходы на зарплату в сумме

    public function getTotalEmployees()
    {
        $totalEmployees = 0;
        // Для каждого департамента
        foreach ($this->departaments as $departament) {
            // Сумируем работников всех департаментов
            $totalEmployees += $departament->countEmployees();
        }
        return $totalEmployees;
    }

    // Рассход кофе в сумме

    public function getAverageSalary()
    {
        // Средняя зарплата = суммарная зарплата / кол-во департаментов
        $avrSalary = $this->getTotalSalary() / count($this->departaments);

        return $avrSalary;
    }

    // Суммарная производительность

    public function getTotalSalary()
    {
        $salary = 0;
        // Для каждого департамента
        foreach ($this->departaments as $departament) {
            // Сумируем зп всех департаментов
            $salary += $departament->getTotalSalary();
        }
        return $salary;
    }

    // Среднее количество работников по департаментам

    public function getAverageCoffee()
    {
        // Среднее потребление кофе = суммарная потребление кофе / кол-во департаментов
        $avrCoffee = $this->getTotalCoffee() / count($this->departaments);

        return $avrCoffee;
    }

    // Средняя зарплата по департаментам

    public function getTotalCoffee()
    {
        $coffee = 0;
        // Для каждого департамента
        foreach ($this->departaments as $departament) {
            // Суммируем расход кофе у департаментов
            $coffee += $departament->getTotalCoffee();
        }
        return $coffee;
    }

    // Среднее потребление кофе по департаментам

    public function getAverageProduct()
    {
        // Средняя производительность = суммарная производительность / кол-во департаментов
        $avrProduct = $this->getTotalProduct() / count($this->departaments);

        return $avrProduct;
    }

    // Средняя производительность по департаментам

    public function getTotalProduct()
    {
        $product = 0;
        // Для каждого департамента
        foreach ($this->departaments as $departament) {
            // Суммируем производительность каждого департамента
            $product += $departament->getTotalProduct();;
        }
        return $product;
    }

    // Средний расход тугриков на одну страницу по департаментам

    public function getAverageCostPerProduct()
    {
        $avrCostPerProduct = 0;
        // Для каждого департамента
        foreach ($this->departaments as $departament) {
            // Сумируем средний расход
            $avrCostPerProduct += $departament->getAverageCostPerProduct();
        }
        // Средняя стоимость 1 страницы = cредняя стоимость всех департ  / кол-во департаментов
        $avrCostPerProduct = $avrCostPerProduct / count($this->departaments);

        return $avrCostPerProduct;
    }
}

// Антикризисный коммитет
class AnticrisisCommittee
{
    /*
    *  Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров,
    *  преимущественно самого низкого ранга. Если инженер является боссом,
    *  вместо него надо уволить другого инженера, не босса.
    *  */
    public function dismissEngineers($company)
    {
        // Запрашивавем все департаменты в компании
        $departaments = $company->getAllDepartments();

        // Перебираем все департаменты в компании
        foreach ($departaments as $departamentName => $departament) {

            // Берем всех работников определенной профессии          
            $engineers = $departament->findEmployees(get_class (new Engineer));
            // Если таковых нет, переходим к следующему департаменту  
            if (!$engineers) continue;
            
            // Исключаем из списка босса
            $engineers = array_filter($engineers, function ($engineer) {
                                      return ($engineer->getChief() == 0);
                                      });
            /*
            foreach ($engineers as $key => $engineer) {
                if ($engineer->getChief() == 1) {
                    unset($engineers[$key]);
                }
            }*/
            //sort($engineers);

            // Сортируем массив работников по рангу по возрастанию
            usort ($engineers, function ($engineer1, $engineer2) {
                $rank1 = $engineer1->getRank();
                $rank2 = $engineer2->getRank();
                if ($rank1 == $rank2) return 0;
                return ($rank1 > $rank2) ? -1 : 1;
                });

            // Берем первые 40% через array_slice
            $dismissingEngineers = floor(count($engineers) * 0.6);
            $engineers = array_slice($engineers, $dismissingEngineers);

            // Увольняем сотрудников
            foreach ($engineers as $engineer) {
                $departament->dismissEmployee($engineer);
            }
        }
    }

    /*
     *  Увеличить в целях стимуляции умственной деятельности базовую ставку аналитика с 800 до 1100 тугриков,
     *  а количество выпиваемого им кофе с 50 до 75 литров.
     *  */
    public function increaseSalaryRate($company)
    {
        // Запрашивавем все департаменты в компании
        $departaments = $company->getAllDepartments();

        // Перебираем все департаменты в компании
        foreach ($departaments as $departamentName => $departament) {

            // Запрашиваем работников
            $analysts = $departament->findEmployees(get_class (new Analyst));
            //var_dump($analysts);
            // Если таковых нет, переходим к следующему департаменту  
            if (!$analysts) continue;

            // Перебираем $analysts
            foreach ($analysts as $analyst) {

                // Повышаем ставку
                $analyst->setSalaryRate(1100);
                // Повышаем количество выпиваемого им кофе
                $analyst->setCoffeeRate(75);
            }
        }
    }

    /*
     *  В тех департаментах, где руководитель не является аналитиком,
     *  заменить его на аналитика самого высшего ранга из этого департамента 
     *  (а бывшего руководителя вернуть к обычной работе)
     *  */
    public function setAnalystAsChief($company)
    {
        // Запрашивавем все департаменты в компании
        $departaments = $company->getAllDepartments();

        // Перебираем все департаменты в компании
        foreach ($departaments as $departamentName => $departament) {

            // Находим шефа в компании
            $chiefEmployee = $departament->getChief();  //findEmployee("all", "all", 1);
            // Узнаем профессию
            $professionName = $chiefEmployee->getProfession()->getName();
            // Если профессия не Аналитик, начинаем переназначение
            if ($professionName != "Analyst") {
                
                // Берем всех аналитиков
                $analysts = $departament->findEmployees(get_class (new Analyst));
                
                // Если в Департаменте нет аналитиков, переходим к след. департаменту
                if (!isset($analysts[0])) continue;
                
                // Сортируем по рангу, по убыванию
                usort ($analysts, function($a, $b)
                                                    {
                                                        $a = $a->getRank();
                                                        $b = $b->getRank();
                                                        if ($a==$b) return 0;                                                        
                                                        return ($a > $b) ? 1 : -1;
                                                    });
                //var_dump($analysts);
                // Заменяем шефа аналитиком
                $departament->replaceChief($analysts[0]);
            }
        }
    }

    /*  
     *  В каждом департаменте повысить 50% (округляя в большую сторону)
     *  менеджеров 1-го и 2-го ранга на один ранг с целью расширить их полномочия.
     *  */
    public function liftManager($company)
    {
        // Запрашивавем все департаменты в компании
        $departaments = $company->getAllDepartments();

        // Перебираем все департаменты в компании
        foreach ($departaments as $departamentName => $departament) {

            // Берем всех работников определенной профессии          
            $employees = $departament->findEmployees(get_class (new Manager));
            // Если таковых нет, переходим к следующему департаменту  
            if (!$employees) continue;

            // Исключаем из списка менеджеров вышые 2ого ранга
            foreach ($employees as $key => $employee) {
                if ($employee->getRank() > 2) {
                    unset($employees[$key]);
                }
            }
            sort($employees);

            // Берем 50% через array_slice
            $enhancingEmployees = ceil(count($employees) * 0.5);
            $employees = array_slice($employees, $enhancingEmployees);

            // Повышаем сотрудников
            foreach ($employees as $employee) {
                $currentRank = $employee->getRank();
                $employee->setRank($currentRank + 1);
            }
        }
    }
}

// Функция создания компании
function createCompany($name)
{
    // Создаем новый класс компании
    $vector = new Company('$name');

    // Создаем классы департаментов
    $vector->createDepartament('Департамент закупок');
    $vector->createDepartament('Департамент продаж');
    $vector->createDepartament('Департамент рекламы');
    $vector->createDepartament('Департамент логистики');

    // Создаем классы профессий
    $me = new Manager();
    $ma = new Marketer();
    $en = new Engineer();
    $an = new Analyst();

    // Добавляем профессии в масив для последующего создания сотрудников пачкой
    $professions['me'] = $me;
    $professions['ma'] = $ma;
    $professions['en'] = $en;
    $professions['an'] = $an;

    // Лист вакансий: департамент => группы вакансий: кол-во|профессия|ранг|статус_начальника
    $vacancies = array(
        'Департамент закупок' => array('9me1', '3me2', '2me3', '2ma1', '1me2boss'),
        'Департамент продаж' => array('12me1', '6ma1', '3an1', '2an2', '1ma2boss'),
        'Департамент рекламы' => array('15ma1', '10ma2', '8me1', '2en1', '1ma3boss'),
        'Департамент логистики' => array('13me1', '5me2', '5en1', '1me1boss')
    );

    // Для каждого департамента
    foreach ($vacancies as $depName => $vacancyGroup) {

        // Для каждой группы вакансий
        foreach ($vacancyGroup as $vacancy) { //($vacancyGroup as $vacancyName => $vacancyQuantity)

            // Достаем кол-во, профессию, ранг и статус боса из вакансии
            preg_match ('/(\d+)?(\D+)?(\d)?(\w+)?/', $vacancy, $matches);
            $vacancyQuantity = (int)$matches[1];
            $professionIndex = $matches[2];
            $rank = (int)$matches[3];
            if (isset($matches[4]) and $matches[4]=='boss') {
                $chief = 1;
            } else {
                $chief = 0;
            }
            
            // Назначаем профессию
            $profession = $professions[$professionIndex];
            
            // Создаем столько сотрудников, сколько вакансий в группе
            for ($id = 1; $id <= $vacancyQuantity; $id++) {
                // Создаем сотрудника
                $employee = new Employee($profession, $rank, $chief);

                // Запрашиваем в Компании нужный департамент
                $departament = $vector->findDepartamentByName($depName);
                // Добавляем сотрудника в этот Департамент
                $departament->addEmployee($employee);
            }
        }
    }
    // Возвращаем объект Компания
    return $vector;
}

// Класс строки таблицы, хранит не фарматированную строку
class TableRow
{
    private $columns = array();   // строка это массив из колонок

    // Конструктор принимает массив колонок
    public function __construct($columns)
    {
        $this->columns = $columns;
    }

    // Метод возвращает содержимое строки (все ее колоночки)
    public function getColumns()
    {
        return $this->columns;
    }
}

// Класс таблицы
class Table
{
    private $tableRows = array();  // массив объектов Строк
    private $length = 15;           // ширина колонок

    // Добавление строки в таблицу, принимает массив
    public function addRow($row)
    {
        // Создаем новую строку
        $this->tableRows[] = new TableRow($row);
    }

    // Печать таблицы
    public function printTable()
    {
        $caption = 1;   // первая строка - заголовок таблицы

        // Перебираем массив объектов Строк
        foreach ($this->tableRows as $row) {

            $stringRow = "";    // строка для печати
            $columnNumber = 0;  // счетчик колонок

            // Извлекаем колонки из строки
            $columns = $row->getColumns();

            // Форматируем каждую колонку в строке
            foreach ($columns as $column) {

                // Округляем числа до 2х знаков после запятой
                if (is_float($column)) {
                    $column = round($column, 2);
                }
                // Добавляем отступы справа для первой колонки
                if ($columnNumber == 0) {
                    $stringRow .= "\n" . $this->padRight($column, $this->length);
                    // Добавляем оступы слева для остальных колонок
                } else {
                    $stringRow .= $this->padLeft($column, $this->length);
                }
                $columnNumber++;
            }
            // Добавляем черту после заголовка
            if ($caption == 1) {
                $stringRow .= "\n" . $this->formatCaption($columnNumber, $this->length);
            }
            // Выводим строку на печать
            echo "{$stringRow}";

            $caption--; // останется только один заголовок
        }
    }

    // Добавление пробелов слева
    private function padRight($string, $length)
    {
        // Разница между переданной строкой и шириной колонки
        $lenghtDifference = $length - mb_strlen($string);
        // Проверка на отрицательное значение при вычитании
        if ($lenghtDifference >= 0) {
            // Заполняем разницу пробелами
            $string .= str_repeat(" ", $lenghtDifference);
        } else {
            // Если таки отрицательное, обрезаем край строки до ширины колонки
            $string = mb_substr($string, 0, $length);
        }
        return $string;
    }

    // Добавление пробелов справа
    private function padLeft($string, $length)
    {
        // Разница между переданной строкой и шириной колонки
        $lenghtDifference = $length - mb_strlen($string);
        // Проверка на отрицательное значение при вычитании
        if ($lenghtDifference >= 0) {
            // Заполняем разницу пробелами
            $string = str_repeat(" ", $lenghtDifference) . $string;
        } else {
            // Если таки отрицательное, обрезаем край строки до ширины колонки
            $string = mb_substr($string, 0, $length);
        }
        return $string;
    }

    // Делаем горизонтальную черту
    private function formatCaption($columnNumber, $length)
    {
        $string = str_repeat("-", $length * $columnNumber);
        return $string;
    }
}

/*  Вывод таблицы результатов   */

// Функция вывода статистики по компании
function printStatistics($company, $caption)
{

    // Создаем таблицу
    $table = new Table();

    // Заголовок таблицы
    $table->addRow(array("Департамент",
        "сотр.",
        "тугр.",
        "кофе",
        "стр.",
        "тугр./стр.."));

    // Статистика по департаентам
    $departaments = $company->getAllDepartments();
    // Каждый департамент строка
    foreach ($departaments as $departament) {
        unset($columns); // обнуляем массив
        // Заполняем массив строк
        $columns[] = mb_convert_case(mb_substr($departament->name, 12), MB_CASE_TITLE, "UTF-8");
        $columns[] = $departament->countEmployees();
        $columns[] = $departament->getTotalSalary();
        $columns[] = $departament->getTotalCoffee();
        $columns[] = $departament->getTotalProduct();
        $columns[] = $departament->getAverageCostPerProduct();
        // Добавляем строку в таблицу
        $table->addRow($columns);
    }

    // Пустая строка
    unset($columns); // обнуляем массив
    $columns[] = ' ';
    // Добавляем строку в таблицу
    $table->addRow($columns);

    // Среднее для всей компании
    unset($columns); // обнуляем массив
    // Заполняем массив строк
    $columns[] = 'Среднее';
    $columns[] = $company->getAverageEmployees();
    $columns[] = $company->getAverageSalary();
    $columns[] = $company->getAverageCoffee();
    $columns[] = $company->getAverageProduct();
    $columns[] = $company->getAverageCostPerProduct();
    // Добавляем строку в таблицу
    $table->addRow($columns);

    // Всего для всей компании
    unset($columns); // обнуляем массив
    // Заполняем массив строк
    $columns[] = 'Всего';
    $columns[] = $company->getTotalEmployees();
    $columns[] = $company->getTotalSalary();
    $columns[] = $company->getTotalCoffee();
    $columns[] = $company->getTotalProduct();
    // Добавляdем строку в таблицу
    $table->addRow($columns);

    // Выводим на печать заголовок
    echo "{$caption}\n";

    // Выводим таблицу на печать
    $table->printTable();
    echo "\n\n";
}
// Клонирует компанию
function cloneCompany($company)
{
    return clone $company;
}

// Регистрируем Vector Inc на Сейшельских островах
$vector = createCompany('Vector');
printStatistics($vector, "Докризисная статистика");
// Создаем антикризисный коммитет
$anticrisisCommittee = new AnticrisisCommittee();
// Первый набор Антикризисных мер
$vector1 = cloneCompany($vector);
$anticrisisCommittee->dismissEngineers($vector1);
printStatistics($vector1, "Антикризисные меры 1");
// Второй набор Антикризисных мер
$vector2 = cloneCompany($vector);
$anticrisisCommittee->increaseSalaryRate($vector2);
$anticrisisCommittee->setAnalystAsChief($vector2);
printStatistics($vector2, "Антикризисные меры 2");
// Третий набор Антикризисных мер
$vector3 = cloneCompany($vector);
$anticrisisCommittee->liftManager($vector3);
printStatistics($vector3, "Антикризисные меры 3");
//var_dump ($vector);
?>