Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Тестовое задание

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (2): [1] 2 »   

> Без описания
karamba
Отправлено: 16 Июня, 2016 - 21:47:38
Post Id



Гость


Покинул форум
Сообщений всего: 86
Дата рег-ции: Сент. 2010  


Помог: 0 раз(а)




Мне прислали сделать тестовое задание из одной конторы. Я его сделал, но их не устроил результат. Помогите. Я не понимаю почему....
Вот задание:
Цитата:
Написать класс (или группу классов) для возможности логирования определенных сообщений.
- Возможность писать логи в stdout, mysql, файл по выбору. (Выбор осуществляется для всей системы логирования)
- Предусмотреть настройки mysql, пути до файла логирования
- Логи должны содержать:
* Дату и время события (в формате YYYY-MM-DD HH:MM:SS)
* Сообщение логирования (строка, массив, объект, исключение)
Код должен быть написан на языке PHP без использования фреймворков и сторонних библиотек.
Обязательно использование объектно-ориентированного подхода.
Архитектура программы должна быть масштабируема (возможность расширения функционала с минимальными правками существующего кода).

Я написал класс три класса для каждого типа логирования. Привожу код для MySQL

CODE (htmlphp):
скопировать код в буфер обмена
  1. class LogDB {
  2.  
  3.         private $host = 'localhost';
  4.         private $database = 'log';
  5.         private $user = 'root';
  6.         private $password = '';
  7.  
  8.         function __construct() {
  9.         $a = func_get_args();
  10.         $i = func_num_args();
  11.         if (method_exists($this,$f='__construct'.$i)) {
  12.             call_user_func_array(array($this,$f),$a);
  13.         }
  14.     }
  15.  
  16.     private function __construct4($host,$database,$user,$password) {
  17.         $this->host = $host;
  18.         $this->database = $database;
  19.         $this->user = $user;
  20.         $this->password = $password;
  21.     }
  22.  
  23.  
  24.         public function logAdd($entry){
  25.  
  26.                 $entry = date("Y-m-d H:i:s ").serialize($entry);
  27.  
  28.                 $mysqli = new mysqli($this->host, $this->user, $this->password, $this->database);
  29.                 if ($mysqli->connect_error) {
  30.                 die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
  31.                 }
  32.  
  33.                 $mysqli->set_charset("utf8");
  34.                 $mysqli->query("insert into log (log) values('$entry')");
  35.                 if ($mysqli->errno) {
  36.                         die('INSERT Error (' . $mysqli->errno . ') ' . $mysqli->error);
  37.                 }
  38.  
  39.                 $mysqli->close();
  40.         }
  41. }


Они ответили что нет объекто-ориентированного подхода. Почему? Я не пойму, что они хотят
 
 Top
Bio man
Отправлено: 17 Июня, 2016 - 01:53:47
Post Id


Постоянный участник


Покинул форум
Сообщений всего: 2751
Дата рег-ции: Июль 2010  
Откуда: Даугавпилс, Латвия


Помог: 52 раз(а)




karamba пишет:
Почему?
потому что его нет.
в задании четко было сказано как надо делать.
во первых нужно выделить сущности.
- Logger: базовый абстрактный класс или интерфейс.
- StreamLogger: производный от Logger для записи логов в поток. В твоем случае это stdout.
- DBLogger: производный от Logger для записи логов в БД.
- FileLogger: производный от Logger для записи логов в файл.

StreamLogger принимает поток как параметр конструктора (в твоем случае php://stdout), открывает его и по завершению программы закрывает (в деструкторе).

DBLogger принимает параметром конструктора либо внешний объект для работы с БД (пусть будет PDO) либо принимает параметры для подключения к БД, и создает объект PDO сам.
Я бы предпочел первый вариант, он более оптимален в плане расширения. Тут вылезает полиморфизм - мы сможем подменить объект PDO на любой другой производный от PDO, а не хардкодим класс в логере.

FileLogger по сути лишний, так как есть StreamLogger, который может работать и с файловыми потоками.

Плюсом было бы написать логгер в соответствии с PSR-3, так как многие помешаны на PSR, и скорее всего посчитают плюсом.
И обязательно почитай PSR-1 и PSR-2, так как твой код ужасен.

Успехов!
 
 Top
T1grOK
Отправлено: 17 Июня, 2016 - 11:29:48
Post Id



Частый гость


Покинул форум
Сообщений всего: 129
Дата рег-ции: Июнь 2013  


Помог: 7 раз(а)




Для подобных вещей очень кстати использование паттерна Chain of responsibility.


-----
Mysql, Postgresql, Redis, Memcached, Unit Testing, CI, Kohana, Yii, Phalcon, Zend Framework, Joomla, Open Cart, Ymaps, VK Api
 
 Top
Bio man
Отправлено: 17 Июня, 2016 - 13:51:41
Post Id


Постоянный участник


Покинул форум
Сообщений всего: 2751
Дата рег-ции: Июль 2010  
Откуда: Даугавпилс, Латвия


Помог: 52 раз(а)




T1grOK пишет:
Для подобных вещей очень кстати использование паттерна Chain of responsibility.
имхо это переусложнение. в задаче сказано, что писать логи нужно 1 логгером, что делает паттерн неприменимым в данной ситуации.
 
 Top
T1grOK
Отправлено: 17 Июня, 2016 - 16:19:34
Post Id



Частый гость


Покинул форум
Сообщений всего: 129
Дата рег-ции: Июнь 2013  


Помог: 7 раз(а)




Bio man пишет:
что делает паттерн неприменимым в данной ситуации

Все применимо - цепочка из одного звена. Но в любой момент количество звеньев можно нарастить, в чем вижу плюс - предусмотрительность к расширению возможностей.


-----
Mysql, Postgresql, Redis, Memcached, Unit Testing, CI, Kohana, Yii, Phalcon, Zend Framework, Joomla, Open Cart, Ymaps, VK Api
 
 Top
LIME
Отправлено: 17 Июня, 2016 - 19:06:44
Post Id


Активный участник


Покинул форум
Сообщений всего: 10732
Дата рег-ции: Нояб. 2010  


Помог: 322 раз(а)




Bio man пишет:
StreamLogger принимает поток как параметр конструктора
Bio man пишет:
DBLogger принимает параметром конструктора либо внешний объект для работы с БД

тогда уж лучше принимать всем DTO
например объект конфига
чтоб уж интерфейс не плясал в разные стороны
(Добавление)
karamba пишет:
$mysqli = new mysqli
я после этого тут же расхотел отвечать когда первый раз вопрос увидел))
karamba пишет:
Дата рег-ции: Сент. 2010  
karamba попрактикуйся еще ...рано профессионально кодить
 
 Top
Bio man
Отправлено: 17 Июня, 2016 - 21:45:16
Post Id


Постоянный участник


Покинул форум
Сообщений всего: 2751
Дата рег-ции: Июль 2010  
Откуда: Даугавпилс, Латвия


Помог: 52 раз(а)




интерфейс интерфейсом а конструктор конструктором. одно другому не мешает. пусть конструкторы отличаются, не вижу в этом проблемы. тем более, код станет понятнее, если конструктор будет принимать понятные параметры (поток, PDO, параметры БД), нежели универсальный DTO (если я правильно понял, что ты имел в виду под DTO).
LIME пишет:
например объект конфига
тут не соглашусь. как раз наоборот, компоненты должны объявляться в конфиге и конфигурироваться приложением при запуске, т.е. сам объект (логгер) ничего не должен знать о конфиге.

Например:
PHP:
скопировать код в буфер обмена
  1. // config
  2. return [
  3.   'components' => [
  4.     'logger' => [
  5.       'class' => DBLogger::class,
  6.       'table' => 'log',
  7.       'db' => 'app',
  8.       'user' => 'root',
  9.       'password' => '',
  10.     ],
  11.   ],
  12. ];
  13.  
  14. // DBLogger
  15. class DBLogger extends Logger
  16. {
  17.   public function __construct($user, $pass, $db, $table)
  18.   {
  19.     // magic
  20.   }
  21. }
  22.  
  23. class StreamLogger extends Logger
  24. {
  25.   public function __construct($stream)
  26.   {
  27.     // magic
  28.   }
  29. }

LIME пишет:
karamba попрактикуйся еще ...рано профессионально кодить
это уж точно.
(Добавление)
T1grOK пишет:
Все применимо - цепочка из одного звена. Но в любой момент количество звеньев можно нарастить, в чем вижу плюс - предусмотрительность к расширению возможностей.
YAGNI. Когда будет потребность - будем рефакторить, иначе это лишнее переусложнение. Тем более это 1 компонент, добавил класс, добавил по методу в логгеры и в путь.
 
 Top
karamba
Отправлено: 19 Июня, 2016 - 12:49:30
Post Id



Гость


Покинул форум
Сообщений всего: 86
Дата рег-ции: Сент. 2010  


Помог: 0 раз(а)




Bio man пишет:
karamba пишет:
Почему?

во первых нужно выделить сущности.
- Logger: базовый абстрактный класс или интерфейс.
- DBLogger: производный от Logger для записи логов в БД.

DBLogger принимает параметром конструктора либо внешний объект для работы с БД (пусть будет PDO) либо принимает параметры для подключения к БД, и создает объект PDO сам.
Успехов!


Попробовал сделать как вы сказали. Посмотрите пожалуйста, оцените.
Я только не понимаю для чего нужен общий абстрактный класс. Я тоже думал, что нужно замутить что то связанное с наследованием. Но просто если этот супер класс убрать, то ничего не измениться, будет все также работать, значит он никак не влияет на функционал. Для чего он нужен?
Если конструктор класса DBLogger будет принимать внешний PDO объект, то наверное не будет учтено задание, которое гласит, что необходима настройка на БД. А так получится, что об настройке на БД должен будет позаботиться создатель этого внешнего PDO, а не мой класс.
Стоит ли делать перегрузку конструктора или это лишнее? Надо ли сделать деструктор для закрытия PDO или он и так закроется при уничтожении экземпляра класса?

PHP:
скопировать код в буфер обмена
  1. <?PHP
  2.  
  3. abstract class Logger {
  4.         abstract protected function logAdd($entry);
  5. }
  6.  
  7. class DBLogger extends Logger{
  8.  
  9.         private $DBH;
  10.  
  11.         function __construct() {
  12.         $a = func_get_args();
  13.         $i = func_num_args();
  14.         if (method_exists($this,$f='__construct'.$i)) {
  15.             call_user_func_array(array($this,$f),$a);
  16.         }
  17.     }
  18.  
  19.         private function __construct0() {
  20.                 try {
  21.                         $this->DBH = new PDO("mysql:host=localhost;dbname=log", 'root', '');
  22.                 }  
  23.                 catch(PDOException $e) {  
  24.                         echo $e->getMessage();  
  25.                 }
  26.         }
  27.  
  28.         private function __construct4($host,$dbname,$user,$pass) {
  29.                 try {  
  30.                         $this->DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
  31.                 }  
  32.                 catch(PDOException $e) {  
  33.                         echo $e->getMessage();  
  34.                 }
  35.         }
  36.  
  37.         function logAdd($entry) {
  38.                 $entry = date("Y-m-d H:i:s ").serialize($entry);
  39.                 try {
  40.                         $STH = $this->DBH->prepare("INSERT INTO log (log) values (?)");
  41.                         $STH->bindParam(1, $entry);
  42.                         $STH->execute();
  43.                 }
  44.                 catch(PDOException $e) {  
  45.                         echo $e->getMessage();  
  46.                 }
  47.         }
  48. }
  49.  
  50. $dbLog = new DBLogger();
  51. $dbLog->logAdd("I use OOP");
  52.  
  53. ?>
 
 Top
OrmaJever Модератор
Отправлено: 19 Июня, 2016 - 13:16:01
Post Id



Активный участник


Покинул форум
Сообщений всего: 7540
Дата рег-ции: Янв. 2010  
Откуда: Чернигов


Помог: 299 раз(а)




я бы наверное вот так сделал
PHP:
скопировать код в буфер обмена
  1. abstract class Logger
  2. {
  3.         protected $text;
  4.  
  5.         public function log( $entry )
  6.         {
  7.                 $this->text = date("[Y-m-d H:i:s] ").serialize($entry);
  8.         }
  9.  
  10.         public function write();
  11. }
  12.  
  13. class FileLoger extends Logger
  14. {
  15.         private $path;
  16.  
  17.         public function __construct( $path )
  18.         {
  19.                 if( !file_exists($path) ) {
  20.                         throw new Exception('File not exists: ' . $path);
  21.                 }
  22.         }
  23.  
  24.         public function write()
  25.         {
  26.                 return file_put_contents($this->path, $this->text . "\n", FILE_APPEND);
  27.         }
  28. }
  29.  
  30. class MysqlLoger extends Logger
  31. {
  32.         private $mysqli;
  33.  
  34.         public function __construct( $user, $pass, $dbname )
  35.         {
  36.                 $this->mysqli = new mysqli($user, $pass, $dbname);
  37.  
  38.                 if( $this->mysqli->connect_errno ) {
  39.                         throw new Exception('Mysqli comment error: ' . $this->mysqli->connect_error);
  40.                 }
  41.         }
  42.  
  43.         public function write()
  44.         {
  45.                 $stmt = $mysqli->prepare('INSERT INTO log (text) values (?)');
  46.                 $stmt->bindValue('s', $this->text);
  47.                 return $stmt->execute();
  48.         }
  49. }
  50.  
  51. class stdoutLogger extends Logger
  52. {
  53.         // ...
  54. }
  55.  
  56. $fileLogger = new FileLoger('./error.log');
  57. $fileLogger->log('случилась беда');
  58. $fileLogger->write();
  59.  
  60. $mysqlLogger = new MysqlLoger('user', 'pass');
  61. $mysqlLogger->log('ойойой');
  62. $mysqlLogger->write();
  63.  


-----
Если вы хотя бы 3-4 раза не решите всё выкинуть и начать заново - вы явно что-то делаете не так.
 
 Top
karamba
Отправлено: 19 Июня, 2016 - 17:38:38
Post Id



Гость


Покинул форум
Сообщений всего: 86
Дата рег-ции: Сент. 2010  


Помог: 0 раз(а)




Да, вытащить сериализацию в базовый класс наверное можно, чтобы был в нем какой то смысл.
Я так понял, что использовать mysqli это уже не модно, надо через PDO.
И метод log лучше, чтобы вызывался прямо в write, чтобы ради одной записи не использовать два метода.
Почему если такого файла на диске нет, то просто не создать его?
 
 Top
Bio man
Отправлено: 19 Июня, 2016 - 17:42:11
Post Id


Постоянный участник


Покинул форум
Сообщений всего: 2751
Дата рег-ции: Июль 2010  
Откуда: Даугавпилс, Латвия


Помог: 52 раз(а)




Что это за хрень с __construct0 итд?
karamba пишет:
Я только не понимаю для чего нужен общий абстрактный класс.
для полиморфизма. в таком случае мы работаем с любым логгером, будто он является абстрактным логгером.
Почитай основы ООП, такие вещи ты должен знать прежде чем говорить что твое ООП - ООП
https://www[dot]youtube[dot]com/user/pro[dot][dot][dot]00fox2/playlists
 
 Top
Viper
Отправлено: 19 Июня, 2016 - 18:54:31
Post Id



Активный участник


Покинул форум
Сообщений всего: 4555
Дата рег-ции: Февр. 2007  
Откуда: Симферополь


Помог: 98 раз(а)




karamba пишет:
И метод log лучше, чтобы вызывался прямо в write, чтобы ради одной записи не использовать два метода.
наоборот. write() убрать и делать это в log() да + добавить возможность указания типа логгера. ИМХО

OrmaJever пишет:
$mysqlLogger = new MysqlLoger('user', 'pass');
ой ли? Если имело смысл использовать разные базюльки(в том числе и удаленный вариант), то смысла нет ибо DSN куда передавать?

И да, как уже было замечено ранее, если файла нет, то создать. Рыгать исключение при отсутствии файла логгера...

Ну и для полного комплекта syslog ещё можно добавить.


-----
Список фильмов с описанием, блекджеком и... для Joomla? -> https://киноархив[dot]com
Демо нового движка для сайта php.su -> php[dot]su, проект на гитхабе
 
 Top
karamba
Отправлено: 19 Июня, 2016 - 19:53:50
Post Id



Гость


Покинул форум
Сообщений всего: 86
Дата рег-ции: Сент. 2010  


Помог: 0 раз(а)




Bio man пишет:
Что это за хрень с __construct0 итд?
karamba пишет:
Я только не понимаю для чего нужен общий абстрактный класс.
для полиморфизма. в таком случае мы работаем с любым логгером, будто он является абстрактным логгером.
Почитай основы ООП, такие вещи ты должен знать прежде чем говорить что твое ООП - ООП
https://www.youtube.com/user/pro100fox2/playlists


Всмысле за хрень с __construct0 итд? Это так реализована перегрузка конструктора. Насколько я понял в PHP нет обычной перегрузки конструктора.

Как будет использоваться полиморфизм в данном случае? В моем абстрактом классе нет ни одного поля или неабстрактного метода. Если мы создадим экземпляр каждого типа логирования и запишем в массив. Будем массив перебирать и вызывать метод logAdd(), то он будет одинаково работать и при существовании базового класса и без него.
 
 Top
Viper
Отправлено: 19 Июня, 2016 - 21:05:25
Post Id



Активный участник


Покинул форум
Сообщений всего: 4555
Дата рег-ции: Февр. 2007  
Откуда: Симферополь


Помог: 98 раз(а)




karamba пишет:
Это так реализована перегрузка конструктора.
это не правильно.


-----
Список фильмов с описанием, блекджеком и... для Joomla? -> https://киноархив[dot]com
Демо нового движка для сайта php.su -> php[dot]su, проект на гитхабе
 
 Top
karamba
Отправлено: 20 Июня, 2016 - 09:17:32
Post Id



Гость


Покинул форум
Сообщений всего: 86
Дата рег-ции: Сент. 2010  


Помог: 0 раз(а)




Viper пишет:
karamba пишет:
Это так реализована перегрузка конструктора.
это не правильно.

Всмысле неправильно? А как еще сделать перегрузку конструктора?
 
 Top
Страниц (2): [1] 2 »
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Объектно-ориентированное программирование »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB