|
|
|
| Доброго времени суток.
Пишу небольшой сайтик на ООП. Структура примерно такая: есть 3 файла model.php,view.php, controller.php. В этих файлах находяться одноименные классы. Фактически весь сайт это эти 3 файла(не считая шаблонов и т.п.) На данный момент у меня один из файлов controller превысил 10кБ и гложут мысли для каждой нужды создавать отдельный класс в отдельном файле. На данный момент в классе контроллер содержаться все методы необходимые для функционирования сайта(метод вывода контекста главных страниц на экран, метод регистрации, метод авторизации и пр.)
Может кто сталкивался и подскажет как видут себя хостинги при работе с объектами больших классов и есть ли порог при котором стоит класс разбивать на несколько классов? | |
|
|
|
|
|
|
|
для: tvv123456
(04.01.2013 в 18:13)
| | стоит разбивать для более грамотной архитектуры, а про 10кб это очень смешно. | |
|
|
|
|
|
|
|
для: CrazyAngel
(05.01.2013 в 08:26)
| | Как раз если будешь разбивать, то в архитектуре можно запутаться, а так: управляющая часть в классе controller, все запросы к базе в model, вся внешняя часть определяется в view и в шаблонах, и при необходимости приходиться менять только один файл.
Если 10 кб смешно, то приведите ваш аргументированный ответ: какой оптимальный объем, чтобы интерпритатор не "подавился"? | |
|
|
|
|
|
|
|
для: tvv123456
(05.01.2013 в 18:27)
| | выкладывайте код, посмотрим и подумаем. но вообще, если один класс-контроллер на весь сайт, то это либо микро-сайт, либо кривая архитектура. | |
|
|
|
|
|
|
|
для: psychomc
(05.01.2013 в 18:33)
| | Конечно для каждой директории/надобности свой контроллер, у меня пока их 2 - для авторизованных юзеров и не авторизованных
Стремно выкладывать такой листинг(много НО в нем), но раз просили:
<?
abstract class abstractController
{
//Постраничная навигация
function pageNavigation($page,$count_elements)
{
$num = (int)pageNum;
$count_pages = ceil($count_elements/$num);
//проверка номера страницы(если страница больше чем последняя выводим последнюю
if($page<=0 || !is_numeric($page)) $page = $this->page = 1;
if(($page-1)*$num >= $count_elements) $page=$count_pages;
$start = ($page-1)*$num;
if($start<0) $start = 0;
$result['forModel'] = "LIMIT ".(int)$start.",".(int)$num;
$param = array();
$param['countPages'] = $count_pages;
$param['current'] = $page;
$result['forView'] = $param;
return $result;
}
//Если страница не найдена
function notFound()
{
$this->view->pageNotFound();
}
//Отправка почты
function sendMail($to,$subject,$from,$message,$type='text/plain',$charset='windows-1251')
{
$headers = "Content-type:".$type."; charset=".$charset." \r\n";
$headers .= "From: ".$from."\r\n";
if(is_array($to))
{
foreach($to as $value) $res = mail($value,$subject,$message,$headers);
}
else $res = mail($to,$subject,$message,$headers);
return $res;
}
}
class controller extends abstractController
{
function __construct()
{
$this->model = new model();
$this->view = new view();
}
//Перенаправляем на выбранную категорию
function viewCategory($cat)
{
(int)$cat>0?header("Location: /article/cat/".(int)$cat):header("Location: /article");
exit;
}
//поиск статей
function searchArticles()
{
$cat = @(int)$_GET['cat'];
$phrase = @$_GET['phrase'];
$phrase = preg_replace("|[\s]+|"," ",trim($phrase));
if(empty($phrase)) return $this->viewCategory($cat);
$phrase = substr(strip_tags($phrase),0,63);
$this->view->smarty->assign('phrase',$phrase);
$this->view->setListCat($this->model->catArt());
$this->view->setCurrentCat((int)$cat);
$model = $this->model->searchArticles($phrase,$cat);
// if($model == false) return $this->notFound();
$this->view->listArticles($model);
}
//выводим статьи в зависимости от постраничной навигации
function article($id_art=false,$page=false,$cat=false)
{
if($id_art==false || empty($id_art))
{
$this->view->setListCat($this->model->catArt());
$this->view->setCurrentCat((int)$cat);
$nav = $this->pageNavigation($page,$this->model->countArt($cat));
$model = $this->model->listArt($cat,$nav['forModel']);
if($model == false) return $this->notFound();
if((int)$cat != false) $this->view->cat=1;
$this->view->pageList($nav['forView']);
$this->view->listArticles($model);
}
else
{
$model= $this->model->viewArticle($id_art);
if($model == false) return $this->notFound();
$comments = $this->model->artComments($model['id']);
$this->view->viewArticle($model,$comments);
}
}
//Выводим контент для главных страниц
function content($idenPage)
{
$model = $this->model->content($idenPage);
if($model == false) return $this->notFound();
$this->view->content($model);
}
//Регистрация пользователей на сайте
//ДИКО ВИДЕТЬ ЧТО ЗДЕСЬ СООБЩЕНИЯ ДЛЯ ПОЛЬЗОВАТЕЛЯ, НО ОБЕЩАЮ ЭТО ПРОСТО ВРЕМЕННО
function reg()
{
if(!isset($_REQUEST['reg_go']))
{
if(isset($_REQUEST['checkMail']))
{
if($this->model->reg('checkMail',$_REQUEST['checkMail'])) $this->view->reg('successRes'); else $this->view->reg('successRes',1);
return true;
}
$this->view->reg();
}
else
{
$errors = array();
if($this->model->reg('checkLogin',array('login'=>$_REQUEST['login'],'email'=>$_REQUEST['email'])))
{
$errors[] = "Уже существует пользователь с таким Логином или E-mail";
}
if(!preg_match('|^[A-z0-9_-]{1,255}$|',$_REQUEST['login']))
{
$errors[] = "Некорректный Логин. Логин может содержать цифры, латинские буквы, а также нижнее подчеркивание и дефис.";
}
if(!preg_match("|^[A-z0-9-_.]+[@][A-z0-9-_.]+[\.][A-z]+|",$_REQUEST['email']))
{
$errors[] = "Некорректный e-mail.";
}
if($_REQUEST['pass'] != $_REQUEST['repass'])
{
$errors[] = 'Не совпадают значения полей "Введите пароль" и "Повторите пароль".';
}
if(strlen($_REQUEST['pass'])<6)
{
$errors[] = "Короткий пароль. Пароль должен состоять минимум из 6 символов.";
}
if(!isset($_SESSION['captcha_keystring']) || empty($_SESSION['captcha_keystring']) || $_SESSION['captcha_keystring'] !== $_POST['s'])
{
$errors[] = "Вы неверно ввели символы с картинки!";
}
if(!isset($_REQUEST['rules']) || $_REQUEST['rules']!=1)
{
$errors[] = "Подтвердите ваше согласие с <a href='/content/rules' target='_blank'>правилами</a> сайта.";
}
$_SESSION['captcha_keystring'] = 1;//обнуляем капчу
if(count($errors)> 0) {$this->view->reg('errors',$errors); return false;}
srand();
for($checkMail = ''; strlen($checkMail) < 6; $checkMail .= rand(1,2) == 1 ? chr(rand(65,90)) : chr(rand(97,122)));
$hash = md5($_REQUEST['email'].$checkMail);
$text = $this->model->reg('insertUser',$hash);
$link = "<a href='http://".$_SERVER['SERVER_NAME']."/reg?checkMail=".$hash."'>http://".$_SERVER['SERVER_NAME']."/reg?checkMail=".$hash."</a>";
$text = str_replace('[link]',$link,$text);
$headers = "from:".adminMail."\r\nContent-type:text/html;Charset=windows-1251\r\n";
mail($_REQUEST['email'],"Подтверждение регистрации на медицинском сайте",$text,$headers);
$this->view->reg('success');
}
}
/*===========КАБИНЕТ ПОЛЬЗОВАТЕЛЯ============*/
function checkAuthData()
{
if(!isset($_POST['go_auth'])) return $this->view->fail_auth();
if(!($res = $this->model->checkAuthData()))
{
return $this->view->fail_auth(1);
}
else
{
if($res['ban'] == 1) return $this->view->fail_auth('ban');
$_SESSION['user_auth_success'] = 9856;
$_SESSION['user_id'] = $res['id'];
foreach($res as $key=>$val)
{
if($key!='id') $_SESSION[$key] = $val;
}
$_SESSION['ip']=md5(GetRealIp().$_SERVER['HTTP_USER_AGENT']);
header('Location: /usercab/');
exit;
}
}
//показываем информацию по выбранному пользователю
function viewUserData($login)
{
$status = false;
if(isset($_POST['goResponse']))
{
if(!isset($_POST['response']) || empty($_POST['response'])) $status = 1;
elseif(!isset($_SESSION['user_id']) || (int)$_SESSION['user_id'] == 0) $status = 2;
else {
if($this->model->insertResponse($login,(int)$_SESSION['user_id'],$_POST['response']))
{header("Location:/user/$login");exit();}
else $status = 3;
}
}
$userData = $this->model->userData($login);
$responses = $this->model->responseList($userData['id']);
$this->view->viewUserData($userData,$status,$responses);
}
function comment()
{
if(isset($_SESSION['user_id']) && (int)$_SESSION['user_id'] != 0 && isset($_POST['idArt']) && $_POST['idArt'] != 0 && isset($_POST['text']) && !empty($_POST['text']))
{
$this->model->insertComment();
}
header("Location: ".$_SERVER['HTTP_REFERER']);
}
}
|
пожалуйста :) листинг контроллера. Если поможете улучшить буду только признателен. Это минимум для неавторизированного пользователя
думаю никто не будет разбираться в этом коде, но раз просили :)))
А если серьезно я не вникал в суть работы железа именно с объектами, но насколько я представляю, при создании объекта все методы класса забивают себе теплое местечко в оперативке сервера?
Интересует меня: нужно ли разбивать контроллер, чтобы не перегрузить хост.
| |
|
|
|
|
|
|
|
для: tvv123456
(05.01.2013 в 18:58)
| | как по мне, так pageNavigation и sendMail это вообще не из той оперы. это должны быть отдельные классы, никак не связанные с контроллером. pageNavigation это вообще ближе по логике к модели, а sendMail - явно утилиты.
notFound я бы вынес во frontController, в котором бы были как минимум общий конфиг и маршрутизация.
ну и вообще, у вас толстый контроллер, в нем явно лежит функционал, который должен быть в моделях. mvc ради mvc это плохо
p.s обязательно используйте модификаторы доступа public/protected/private. а то код читается плохо, и инкапсуляции как таковой нет (потому что по дефолту public, а им лучше не злоупотреблять как и private).
pp.s я бы меньше загонялся на вашем месте на нагрузке на сервер, а больше уделял бы лаконичности и грамотности кода (если конечно это не высоконагруженное приложение). лучше конечно, чтобы в совокупности была и хорошая производительность, но куда важнее именно читабельность. кому-то в этом коде потом скорее всего придется разбираться, с большой вероятностью Вам же, и если код будет плохим, сопровождаться он будет долго. а время программиста намного дороже компьютерного | |
|
|
|
|
|
|
|
для: psychomc
(05.01.2013 в 19:26)
| | pageNavigation - и есть отдельный класс
sendMail - пока функционал не предусматривает каких либо расширенных опций кроме как отправки текстовых сообщения
> в нем явно лежит функционал, который должен быть в моделях
согласен, но в нем больше Вида :), это исправляю по-тихоньку
а так прислушаюсь к вашим советам. Может еще кто-нибудь что-нибудь подкинет?
P.S.Но главный вопрос: оптимальный размер класса. Давайте не будем уходить от темы | |
|
|
|
|
|
|
|
для: tvv123456
(05.01.2013 в 19:34)
| | >P.S.Но главный вопрос: оптимальный размер класса. Давайте не будем уходить от темы
никакой он не главный. я не знаю такого понятия, как оптимальный размер класса. где Вы вообще это взяли? есть рекомендуемая длина строки кода. нельзя размер класса подгонять под какие-то подобные требования, всё зависит от сущности, которую класс описывает. размер может быть как 1, так и 50 килобайт. главное, чтобы класс делал именно то, что от него требуется и ничего лишнего. и была бы гибкая связь с другими классами (наследование не всегда хорошо). и всё, не забивайте себе голову подобной ерундой, лучше учите ООП, паттерны, анализируйте чужой код и будет Вам счастье. | |
|
|
|
|
|
|
|
для: psychomc
(05.01.2013 в 19:44)
| | нет понятие оптимальный размер класса, но есть понятия: читабильность и производительность кода.
Можно давать переменным именна которые будут понятны стороннему($message,$userId и тп.) а можно сокращать объем кода($m,$ui...). Уменьшение лишней писанины раз в 5 приведет к заметному изменению отношения читабельность/скорость. Меня в данной теме инетересовало мнение людей работающих с большими проектами и было интересно тянут ли сервера объем пхп кода более чем в 200-500кБ. | |
|
|
|
|
|
|
|
для: tvv123456
(05.01.2013 в 22:05)
| | хм, всё равно не могу понять в чем собственно проблема. пишите код с нормальными переменными, а потом, если уж так важна производительность, пройдитесь по нему обфускатором, прежде чем залить на сервер. естественно сделав предварительно копию
и еще, разработчики php заявляют, что в новых версиях существенно увеличилась производительность самого интерпретатора. думаю, это еще один аргумент за то, чтобы не загоняться из-за каждого байта памяти | |
|
|
|
|
|
|
|
для: tvv123456
(05.01.2013 в 19:34)
| | Скажем так, 500Кб классы в продакшен-версии вполне допустимы. Классы и объекты, занимают определенный объем памяти, каждый скрипт ограничен по потребляемой памяти и времени. Если вашим классам не хватит времени или памяти - вам вывалится соответствующее сообщение об ошибке.
На этапе разработки, лучше, если ваши классы не превышают 500 строк (в продакшен версии или в релизе библиотеки файлы можно аггергировать в более крупные). | |
|
|
|
|
|
|
|
для: cheops
(05.01.2013 в 21:19)
| | лучший ответ :), спасибо. | |
|
|
|
|
|
|
|
для: tvv123456
(05.01.2013 в 22:00)
| | Зря вы в абстрактном классе кучу кода нагородили. Он у вас далеко не абстрактный. В абстрактном классе опишите методы, свойства, но возможностями им не давайте, это сделают наследники. | |
|
|
|
|
|
|
|
для: ols
(06.01.2013 в 01:22)
| | вообще это нормальная практика, если конечно методы этого абстрактного класса будут использоваться в потомках. другое дело, что у автора сам по себе этот абстрактный класс с как минимум странным функционалом. для того, о чем говорите Вы, обычно используются интерфейсы (interface), вот там никакой реализации быть не должно само собой | |
|
|
|
|
|
|
|
для: tvv123456
(04.01.2013 в 18:13)
| | Используйте наследование, создайте базовый класс-контроллер с методами, которые потребуются всем классам, а для конкретных модулей и даже отдельных страниц модулей (например, список и детальная информация) используйте отдельные классы-контроллеры, унаследованные от базового класса. | |
|
|
|
|
|
|
|
для: cheops
(05.01.2013 в 10:03)
| | да так впринципе и есть.
Есть базовый файл abstract.php в нем содержатся классы abstractControler и т.п., и классы контролер и др. наследуют их. Т.о., есть отдельные файлы/классы controler,view,model ~.php для общего раздела, для раздела usercab и т.п
Интересно просто. по сути при каждом обращении клиента изначально срабатывает компилятор, и не перезгрузит ли он систему? А если это случается, то какой критичный объем класса, чтобы можно было создавать объект не затрудняя работу сервера(причем на сервере не один мой сайт, а еще 1000 таких)
А разве когда создаем объект, то абстракт.класс не займет ресурсы своими методами, которые в принципе не могут использоваться конкретно в данном дочернем классе? | |
|
|
|
|
|
|
|
для: tvv123456
(05.01.2013 в 18:24)
| | кстати, плохая практика хранить в одном файле несколько классов. | |
|
|
|
|
|
|
|
для: psychomc
(05.01.2013 в 18:34)
| | согласен.
Но у меня абстрактные классы включают в себя меньше 10 методов. Из-за смарти почему-то не работает:
<?
function __autoload($class_name) {
$filename = strtolower($class_name) . '.php';
$file = $_SERVER['DOCUMENT_ROOT']."/".my_class_path."/".$filename;
if (file_exists($file) == false) {
echo $file;
return false;
}
include ($file);
}
|
а вручную подключать каждый файл с абстрактным классом из 10 методов лень :)
по поводу критичности размера класса сказать можете что-нибудь? | |
|
|
|
|
|
|
|
для: tvv123456
(05.01.2013 в 18:49)
| | по поводу смарти всё понятно. юзайте вот эту функцию http://php.net/manual/ru/function.spl-autoload-register.php и проблема исчезнет. заодно создайте класса loader, с методами register и unregister. | |
|
|
|
|
|
|
|
для: psychomc
(05.01.2013 в 19:02)
| | А вот за это спасибо :) | |
|
|
|
|
|
|
|
для: tvv123456
(05.01.2013 в 18:24)
| | С чего вы взяли, что для сервера самым важным будет размер файла?
У Вас больше ни с чем проблем нет?
Я ни разу не встречал проблем с размером файла скрипта. Разве что не удобно мотать вниз-вверх. Да и то современные IDE эту проблему полностью решают. Ну и к нагрузке на сервер это не имеет отношения.
Нагрузка на сервер идет от функционала, а не от размера. Можно и в 1ом килобайте зарядить рекурсивный обход дерева в MySQL и мало не покажется.
Делайте так, чтоб вам было удобно и понятно. Размер файла - это последний вопрос, который вас будет интересовать. | |
|
|
|
|