<?php
abstract class Worker
{
protected $salary;
protected $coffee;
protected $pages;
protected $rank;
protected $isBoss = FALSE;
public function setSalary($x) { $this->salary = $x; }
public function setCoffee($x) { $this->coffee = $x; }
public function setIsBoss($x) { $this->isBoss = $x; }
public function setRank($x) { $this->rank = $x; }
public function getRank() { return $this->rank; }
public function getIsBoss() { return $this->isBoss; }
public function __construct($rank)
{
$this->rank = $rank;
}
//использую статичесую функцию со new static для создания экземпляров класса.
//иными словами, буду вызывать эту функцию через подклассы и создавать объекты
public static function create($rank, $bodyCount)
{
$arrayOfMen = [];
for($i = 1; $i <= $bodyCount; $i++){
$newMan = new static($rank);
$arrayOfMen[] = $newMan;
}
return $arrayOfMen;
}
//функция, которая будет давать статистику по персонажу
public function getStatistic()
{
$rankCoefficient = 0; // коэффициент для умножения результатов по рангам
switch ($this->rank):
case 1:
$rankCoefficient = 1;
break;
case 2:
$rankCoefficient = 1.25;
break;
case 3:
$rankCoefficient = 1.5;
break;
endswitch;
$bossCoefficient = 0; //коэффициент для босса
switch ($this->isBoss):
case FALSE:
$bossCoefficient = 1;
break;
case TRUE:
$bossCoefficient = 2;
break;
endswitch;
$statistic = [
"salary" => $this->salary * $rankCoefficient * $bossCoefficient,
"coffee" => $this->coffee * $bossCoefficient,
"pages" => $this->pages,
];
//проверяю, босс ли, чтобы стереть его страницы
if ($this->isBoss) {
$statistic["pages"] = 0;
}
return $statistic;
}
public static
function makeHimBoss
(array $arrayOfMen) {
$futureBoss = $arrayOfMen[0];
$futureBoss->isBoss = TRUE;
}
}
class Marketing extends Worker
{
protected $salary = 400;
protected $coffee = 15;
protected $pages = 150;
}
class Management extends Worker
{
public $salary = 500;
public $coffee = 20;
public $pages = 200;
}
class Engineer extends Worker
{
protected $salary = 200;
protected $coffee = 5;
protected $pages = 50;
}
class Analysis extends Worker
{
protected $salary = 800;
protected $coffee = 50;
protected $pages = 5;
}
class Department
{
//в этом массиве хранятся все сотрудники
public $staff = [];
//тут добавляю сотрудников в этот массив
public function addNewStaffMember
(array $men) {
}
public function __clone()
{
foreach ($this->staff as & $man) {
$man = clone $man;
}
}
//увольняю(для антикризисных мер)
public function fireStaffMember(Worker $fired)
{
foreach($this->staff as $id => $man){
//тут долго думал, в итоге использую "===" для проверки того, идентичные ли объекты. Правильно всё?
if($man === $fired) { unset($this->staff[$id]); } }
}
//через эту функцию вывожу статистику по департаменту
public function getStatisticOfDepartment()
{
$totalSalary = $totalCoffee = $totalPages = $totalBodies = 0;
foreach($this->staff as $man){
$totalSalary += $man->getStatistic()["salary"];
$totalCoffee += $man->getStatistic()["coffee"];
$totalPages += $man->getStatistic()["pages"];
$totalBodies++;
}
$resultStats =
[
"bodies" => $totalBodies,
"salary" => $totalSalary,
"coffee" => $totalCoffee,
"pages" => $totalPages,
];
//возвращаю массив со статистикой
return $resultStats;
}
}
///// для таблицы ----------------------------------------------------------------------
//функция аналог str_pad, только для кириллицы (взял с инета, т.к. стандартная str_pad не работает с кириллицей)
function mb_str_pad($str, $pad_len, $pad_str = ' ', $dir = STR_PAD_RIGHT)
{
$padBefore = $dir === STR_PAD_BOTH || $dir === STR_PAD_LEFT;
$padAfter = $dir === STR_PAD_BOTH || $dir === STR_PAD_RIGHT;
$targetLen = $padBefore && $padAfter ? $pad_len / 2 : $pad_len;
$repeatTimes = ceil($targetLen / $strToRepeatLen); $before = $padBefore ?
mb_substr($repeatedString, 0, floor($targetLen)) : ''; $after = $padAfter ?
mb_substr($repeatedString, 0, ceil($targetLen)) : ''; return $before . $str . $after;
}
//пишу функцию для вставки пробелов справа
function padRight($string, $length)
{
if($spaces>0) { $string=mb_str_pad
($string, mb_strlen($string) + $spaces, " ", STR_PAD_RIGHT
); } return $string;
}
//пишу функцию для вставки пробелов слева
function padLeft($string, $length)
{
if($spaces>0) { $string=mb_str_pad
($string, mb_strlen($string) + $spaces, " ", STR_PAD_LEFT
); } return $string;
}
///// для таблицы ---------------------------------------------------------------------- КОНЕЦ
//Заполняем департменты рабочими
$BuyingDep = new Department();
$men = Management::create(1, 9);
$BuyingDep->addNewStaffMember($men);
$men = Management::create(2, 3);
$BuyingDep->addNewStaffMember($men);
$men = Management::create(3, 2);
$BuyingDep->addNewStaffMember($men);
$men = Marketing::create(1, 2);
$BuyingDep->addNewStaffMember($men);
$men = Management::create(2, 1);
Worker::makeHimBoss($men);
$BuyingDep->addNewStaffMember($men);
$SellingDep = new Department();
$men = Management::create(1, 12);
$SellingDep->addNewStaffMember($men);
$men = Marketing::create(1, 6);
$SellingDep->addNewStaffMember($men);
$men = Analysis::create(1, 3);
$SellingDep->addNewStaffMember($men);
$men = Analysis::create(2, 2);
$SellingDep->addNewStaffMember($men);
$men = Marketing::create(2, 1);
Worker::makeHimBoss($men);
$SellingDep->addNewStaffMember($men);
$AdsDep = new Department();
$men = Marketing::create(1, 15);
$AdsDep->addNewStaffMember($men);
$men = Marketing::create(2, 10);
$AdsDep->addNewStaffMember($men);
$men = Management::create(1, 8);
$AdsDep->addNewStaffMember($men);
$men = Engineer::create(1, 2);
$AdsDep->addNewStaffMember($men);
$men = Marketing::create(3, 1);
Worker::makeHimBoss($men);
$AdsDep->addNewStaffMember($men);
$LogisticsDep = new Department();
$men = Management::create(1, 13);
$LogisticsDep->addNewStaffMember($men);
$men = Management::create(2, 5);
$LogisticsDep->addNewStaffMember($men);
$men = Engineer::create(1, 5);
$LogisticsDep->addNewStaffMember($men);
$men = Management::create(1, 1);
Worker::makeHimBoss($men);
$LogisticsDep->addNewStaffMember($men);
//функция вывода Таблицы
function showTable($BuyingDep, $SellingDep, $AdsDep, $LogisticsDep)
{
//два типа колонок
$col1 = 25;
$col2 = 15;
//верхняя строка таблицы
echo padRight("Департамент", $col1) .
padLeft("сотр.", $col2) .
padLeft("тугр.", $col2) .
padLeft("кофе", $col2) .
padLeft("стр.", $col2) .
padLeft("тугр./стр.", $col2) .
"\n";
$totalBodies = $totalSalary = $totalCoffee = $totalPages = $totalBalance = 0;
//делаю массив массивов статистики по всем департаментам
$statistics = [
"Закупок" => $BuyingDep->getStatisticOfDepartment(),
"Продаж" => $SellingDep->getStatisticOfDepartment(),
"Рекламы" => $AdsDep->getStatisticOfDepartment(),
"Логистики" => $LogisticsDep->getStatisticOfDepartment(),
];
//прохожусь по массиву массивов
foreach ($statistics as $department => $datum) {
$balance = round($datum["salary"] / $datum["pages"], 2); echo padRight("$department", $col1) .
padLeft($datum["bodies"], $col2) .
padLeft($datum["salary"], $col2) .
padLeft($datum["coffee"], $col2) .
padLeft($datum["pages"], $col2) .
padLeft($balance, $col2) .
"\n";
$totalBodies += $datum["bodies"];
$totalSalary += $datum["salary"];
$totalCoffee += $datum["coffee"];
$totalPages += $datum["pages"];
$totalBalance += $balance;
}
echo "\n";
//колонка СРЕДНЕЕ
echo padRight("Среднее", $col1) .
padLeft($totalBodies / 4, $col2) .
padLeft($totalSalary / 4, $col2) .
padLeft($totalCoffee / 4, $col2) .
padLeft($totalPages / 4, $col2) .
padLeft($totalBalance / 4, $col2) .
"\n";
//колонка ВСЕГО
echo padRight("Всего", $col1) .
padLeft($totalBodies, $col2) .
padLeft($totalSalary, $col2) .
padLeft($totalCoffee, $col2) .
padLeft($totalPages, $col2) .
padLeft($totalBalance, $col2) .
"\n";
}
showTable($BuyingDep, $SellingDep, $AdsDep, $LogisticsDep);
echo "\n\n\n\n\n";
//антикризисные меры, надо раскоментировать необходимую строчку
executeAction1($BuyingDep, $SellingDep, $AdsDep, $LogisticsDep);
executeAction2($BuyingDep, $SellingDep, $AdsDep, $LogisticsDep);
executeAction3($BuyingDep, $SellingDep, $AdsDep, $LogisticsDep);
//
// АНТИКРИЗИСНЫЕ МЕРЫ ---------------------
//--------------------------------------------------
//
//1. Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров,
// преимущественно самого низкого ранга.
// Если инженер является боссом, вместо него надо уволить другого инженера, не босса.
function executeAction1($BuyingDep, $SellingDep, $AdsDep, $LogisticsDep)
{
$BuyingClone = clone $BuyingDep;
$SellingClone = clone $SellingDep;
$AdsClone =clone $AdsDep;
$LogisticClone = clone $LogisticsDep;
$allDepartments = [$BuyingClone, $SellingClone, $AdsClone, $LogisticClone];
foreach ($allDepartments as $department) {
$allEngineers = 0;
$listOfRank1 = [];
$listOfRank2 = [];
$listOfRank3 = [];
$wasThereAnEngineerBoss = 0;
//прохожусь по департаментам и распределяю инженеров
foreach ($department->staff as $man) {
if ($man instanceof Engineer AND $man->getIsBoss() == FALSE) {
$allEngineers++;
if ($man->getRank() == 1) {
$listOfRank1[] = $man;
} elseif ($man->getRank() == 2) {
$listOfRank2[] = $man;
} elseif ($man->getRank() == 3) {
$listOfRank3[] = $man;
}
} elseif ($man instanceof Engineer AND $man->getIsBoss() == TRUE) {
$wasThereAnEngineerBoss = 1;
}
$allEngineers += $wasThereAnEngineerBoss;
$engineersToFire = ceil($allEngineers * 0.4); $firedCount = 0;
}
//соединяю в один массив, от меньших рангов к большим.
$listByRank = array_merge($listOfRank1, $listOfRank2, $listOfRank3);
if (!empty($listByRank)) { foreach ($department->staff as $id => $man) {
foreach ($listByRank as $fired) {
if ($man === $fired) {
unset($department->staff[$id]); $firedCount++;
}
}
if ($firedCount == $engineersToFire) break;
}
}
}
echo "Solution #1. This is what would happen if we dismissed 40% of our Engineers\n\n";
showTable($BuyingClone, $SellingClone, $AdsClone, $LogisticClone);
echo "\n\n\n\n\n";
}
//2. 2. Увеличить в целях стимуляции умственной деятельности базовую ставку аналитика с 800 до 1100 тугриков,
// а количество выпиваемого им кофе с 50 до 75 литров. В тех департаментах, где руководитель
// не является аналитиком, заменить его на аналитика самого
// высшего ранга из этого департамента (а бывшего руководителя вернуть к обычной работе)
function executeAction2($BuyingDep, $SellingDep, $AdsDep, $LogisticsDep)
{
$BuyingClone = clone $BuyingDep;
$SellingClone = clone $SellingDep;
$AdsClone = clone $AdsDep;
$LogisticClone = clone $LogisticsDep;
$allDepartments = [$BuyingClone, $SellingClone, $AdsClone, $LogisticClone];
//прохожусь по департаментам
foreach($allDepartments as $department) {
$wasThereNotAnalysisBoss = FALSE; //использую эту переменную для того, чтоб унзать, был ли босс Аналитиком
//прохожусь по сотрудникам департаментов
foreach ($department->staff as $man) {
$highestRank = 1;
$highestRankedAnalysisMan = NULL; //эта переменная служит для выявления наиболее ранкнутого аналитика
if ($man instanceof Analysis) {
$man->setSalary(1100);
$man->setCoffee(75);
if ($man->getRank() >= $highestRank) {
$highestRank = $man->getRank();
$highestRankedAnalysisMan = $man;
}
//проверяю, есть ли босс не аналитик, если да, разжалую его
} elseif($man->getIsBoss() == TRUE){
$wasThereNotAnalysisBoss = TRUE;
$exBoss = $man;
}
}
//наиболее ранкнутого инженера повышаю, если $wasThereNotAnalysisBoss показало, что был босс-не-аналитик
if($wasThereNotAnalysisBoss == TRUE AND $highestRankedAnalysisMan != NULL) {
$highestRankedAnalysisMan->setIsBoss(TRUE);
$exBoss->setIsBoss(FALSE);
}
}
echo "Solution #2. This is what would happen if we raised the salary rate of the Analytics.\n\n";
showTable($BuyingClone, $SellingClone, $AdsClone, $LogisticClone);
echo "\n\n\n\n\n";
}
//3. В каждом департаменте повысить 50% (округляя в большую сторону) менеджеров
// 1-го и 2-го ранга на один ранг с целью расширить их полномочия.
function executeAction3($BuyingDep, $SellingDep, $AdsDep, $LogisticsDep)
{
$BuyingClone = clone $BuyingDep;
$SellingClone = clone $SellingDep;
$AdsClone =clone $AdsDep;
$LogisticClone = clone $LogisticsDep;
$allDepartments = [$BuyingClone, $SellingClone, $AdsClone, $LogisticClone];
$allManagersOfRank1 = [];
$allManagersOfRank2 = [];
foreach($allDepartments as $department){
foreach($department->staff as $man){
if($man instanceof Management){
if($man->getRank() == 1) {
$allManagersOfRank1[] = $man;
} elseif($man->getRank() == 2){
$allManagersOfRank2[] = $man;
}
}
}
$toGetPromotedOfRank1 = ceil((count($allManagersOfRank1)+1)*0.5); $toGetPromotedOfRank2 = ceil((count($allManagersOfRank2)+1)*0.5); $alreadyPromotedOfRank1 = 0;
$alreadyPromotedOfRank2 = 0;
foreach($allManagersOfRank1 as $man){
$man->setRank(2);
$alreadyPromotedOfRank1++;
if($toGetPromotedOfRank1 == $alreadyPromotedOfRank1) break;
}
foreach($allManagersOfRank2 as $man){
$man->setRank(3);
$alreadyPromotedOfRank2++;
if($toGetPromotedOfRank2 == $alreadyPromotedOfRank2) break;
}
}
echo "Solution #3. This is what would happen if we promoted half of our Managers.\n\n";
showTable($BuyingClone, $SellingClone, $AdsClone, $LogisticClone);
echo "\n\n\n\n\n";
}