Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP. Практика создания Web-сайтов (второе издание). Авторы: Кузнецов М.В., Симдянов И.В. Объектно-ориентированное программирование на PHP. Авторы: Кузнецов М.В., Симдянов И.В. Программирование. Ступени успешной карьеры. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: ООП насколько большим может быть класс
 
 автор: tvv123456   (04.01.2013 в 18:13)   письмо автору
 
 

Доброго времени суток.
Пишу небольшой сайтик на ООП. Структура примерно такая: есть 3 файла model.php,view.php, controller.php. В этих файлах находяться одноименные классы. Фактически весь сайт это эти 3 файла(не считая шаблонов и т.п.) На данный момент у меня один из файлов controller превысил 10кБ и гложут мысли для каждой нужды создавать отдельный класс в отдельном файле. На данный момент в классе контроллер содержаться все методы необходимые для функционирования сайта(метод вывода контекста главных страниц на экран, метод регистрации, метод авторизации и пр.)

Может кто сталкивался и подскажет как видут себя хостинги при работе с объектами больших классов и есть ли порог при котором стоит класс разбивать на несколько классов?

  Ответить  
 
 автор: CrazyAngel   (05.01.2013 в 08:26)   письмо автору
 
   для: tvv123456   (04.01.2013 в 18:13)
 

стоит разбивать для более грамотной архитектуры, а про 10кб это очень смешно.

  Ответить  
 
 автор: tvv123456   (05.01.2013 в 18:27)   письмо автору
 
   для: CrazyAngel   (05.01.2013 в 08:26)
 

Как раз если будешь разбивать, то в архитектуре можно запутаться, а так: управляющая часть в классе controller, все запросы к базе в model, вся внешняя часть определяется в view и в шаблонах, и при необходимости приходиться менять только один файл.
Если 10 кб смешно, то приведите ваш аргументированный ответ: какой оптимальный объем, чтобы интерпритатор не "подавился"?

  Ответить  
 
 автор: psychomc   (05.01.2013 в 18:33)   письмо автору
 
   для: tvv123456   (05.01.2013 в 18:27)
 

выкладывайте код, посмотрим и подумаем. но вообще, если один класс-контроллер на весь сайт, то это либо микро-сайт, либо кривая архитектура.

  Ответить  
 
 автор: tvv123456   (05.01.2013 в 18:58)   письмо автору
 
   для: 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<=|| !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) == 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'] != && isset($_POST['idArt']) && $_POST['idArt'] != && isset($_POST['text']) && !empty($_POST['text']))
       {
        
$this->model->insertComment();
       }
       
header("Location: ".$_SERVER['HTTP_REFERER']);
    }
}



пожалуйста :) листинг контроллера. Если поможете улучшить буду только признателен. Это минимум для неавторизированного пользователя
думаю никто не будет разбираться в этом коде, но раз просили :)))
А если серьезно я не вникал в суть работы железа именно с объектами, но насколько я представляю, при создании объекта все методы класса забивают себе теплое местечко в оперативке сервера?
Интересует меня: нужно ли разбивать контроллер, чтобы не перегрузить хост.

  Ответить  
 
 автор: psychomc   (05.01.2013 в 19:26)   письмо автору
 
   для: tvv123456   (05.01.2013 в 18:58)
 

как по мне, так pageNavigation и sendMail это вообще не из той оперы. это должны быть отдельные классы, никак не связанные с контроллером. pageNavigation это вообще ближе по логике к модели, а sendMail - явно утилиты.
notFound я бы вынес во frontController, в котором бы были как минимум общий конфиг и маршрутизация.
ну и вообще, у вас толстый контроллер, в нем явно лежит функционал, который должен быть в моделях. mvc ради mvc это плохо

p.s обязательно используйте модификаторы доступа public/protected/private. а то код читается плохо, и инкапсуляции как таковой нет (потому что по дефолту public, а им лучше не злоупотреблять как и private).

pp.s я бы меньше загонялся на вашем месте на нагрузке на сервер, а больше уделял бы лаконичности и грамотности кода (если конечно это не высоконагруженное приложение). лучше конечно, чтобы в совокупности была и хорошая производительность, но куда важнее именно читабельность. кому-то в этом коде потом скорее всего придется разбираться, с большой вероятностью Вам же, и если код будет плохим, сопровождаться он будет долго. а время программиста намного дороже компьютерного

  Ответить  
 
 автор: tvv123456   (05.01.2013 в 19:34)   письмо автору
 
   для: psychomc   (05.01.2013 в 19:26)
 

pageNavigation - и есть отдельный класс
sendMail - пока функционал не предусматривает каких либо расширенных опций кроме как отправки текстовых сообщения
> в нем явно лежит функционал, который должен быть в моделях
согласен, но в нем больше Вида :), это исправляю по-тихоньку
а так прислушаюсь к вашим советам. Может еще кто-нибудь что-нибудь подкинет?

P.S.Но главный вопрос: оптимальный размер класса. Давайте не будем уходить от темы

  Ответить  
 
 автор: psychomc   (05.01.2013 в 19:44)   письмо автору
 
   для: tvv123456   (05.01.2013 в 19:34)
 

>P.S.Но главный вопрос: оптимальный размер класса. Давайте не будем уходить от темы

никакой он не главный. я не знаю такого понятия, как оптимальный размер класса. где Вы вообще это взяли? есть рекомендуемая длина строки кода. нельзя размер класса подгонять под какие-то подобные требования, всё зависит от сущности, которую класс описывает. размер может быть как 1, так и 50 килобайт. главное, чтобы класс делал именно то, что от него требуется и ничего лишнего. и была бы гибкая связь с другими классами (наследование не всегда хорошо). и всё, не забивайте себе голову подобной ерундой, лучше учите ООП, паттерны, анализируйте чужой код и будет Вам счастье.

  Ответить  
 
 автор: tvv123456   (05.01.2013 в 22:05)   письмо автору
 
   для: psychomc   (05.01.2013 в 19:44)
 

нет понятие оптимальный размер класса, но есть понятия: читабильность и производительность кода.
Можно давать переменным именна которые будут понятны стороннему($message,$userId и тп.) а можно сокращать объем кода($m,$ui...). Уменьшение лишней писанины раз в 5 приведет к заметному изменению отношения читабельность/скорость. Меня в данной теме инетересовало мнение людей работающих с большими проектами и было интересно тянут ли сервера объем пхп кода более чем в 200-500кБ.

  Ответить  
 
 автор: psychomc   (05.01.2013 в 22:40)   письмо автору
 
   для: tvv123456   (05.01.2013 в 22:05)
 

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

и еще, разработчики php заявляют, что в новых версиях существенно увеличилась производительность самого интерпретатора. думаю, это еще один аргумент за то, чтобы не загоняться из-за каждого байта памяти

  Ответить  
 
 автор: cheops   (05.01.2013 в 21:19)   письмо автору
 
   для: tvv123456   (05.01.2013 в 19:34)
 

Скажем так, 500Кб классы в продакшен-версии вполне допустимы. Классы и объекты, занимают определенный объем памяти, каждый скрипт ограничен по потребляемой памяти и времени. Если вашим классам не хватит времени или памяти - вам вывалится соответствующее сообщение об ошибке.

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

  Ответить  
 
 автор: tvv123456   (05.01.2013 в 22:00)   письмо автору
 
   для: cheops   (05.01.2013 в 21:19)
 

лучший ответ :), спасибо.

  Ответить  
 
 автор: ols   (06.01.2013 в 01:22)   письмо автору
 
   для: tvv123456   (05.01.2013 в 22:00)
 

Зря вы в абстрактном классе кучу кода нагородили. Он у вас далеко не абстрактный. В абстрактном классе опишите методы, свойства, но возможностями им не давайте, это сделают наследники.

  Ответить  
 
 автор: psychomc   (06.01.2013 в 02:58)   письмо автору
 
   для: ols   (06.01.2013 в 01:22)
 

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

  Ответить  
 
 автор: cheops   (05.01.2013 в 10:03)   письмо автору
 
   для: tvv123456   (04.01.2013 в 18:13)
 

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

  Ответить  
 
 автор: tvv123456   (05.01.2013 в 18:24)   письмо автору
 
   для: cheops   (05.01.2013 в 10:03)
 

да так впринципе и есть.
Есть базовый файл abstract.php в нем содержатся классы abstractControler и т.п., и классы контролер и др. наследуют их. Т.о., есть отдельные файлы/классы controler,view,model ~.php для общего раздела, для раздела usercab и т.п
Интересно просто. по сути при каждом обращении клиента изначально срабатывает компилятор, и не перезгрузит ли он систему? А если это случается, то какой критичный объем класса, чтобы можно было создавать объект не затрудняя работу сервера(причем на сервере не один мой сайт, а еще 1000 таких)
А разве когда создаем объект, то абстракт.класс не займет ресурсы своими методами, которые в принципе не могут использоваться конкретно в данном дочернем классе?

  Ответить  
 
 автор: psychomc   (05.01.2013 в 18:34)   письмо автору
 
   для: tvv123456   (05.01.2013 в 18:24)
 

кстати, плохая практика хранить в одном файле несколько классов.

  Ответить  
 
 автор: tvv123456   (05.01.2013 в 18:49)   письмо автору
 
   для: 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 методов лень :)
по поводу критичности размера класса сказать можете что-нибудь?

  Ответить  
 
 автор: psychomc   (05.01.2013 в 19:02)   письмо автору
 
   для: tvv123456   (05.01.2013 в 18:49)
 

по поводу смарти всё понятно. юзайте вот эту функцию http://php.net/manual/ru/function.spl-autoload-register.php и проблема исчезнет. заодно создайте класса loader, с методами register и unregister.

  Ответить  
 
 автор: tvv123456   (05.01.2013 в 19:11)   письмо автору
 
   для: psychomc   (05.01.2013 в 19:02)
 

А вот за это спасибо :)

  Ответить  
 
 автор: Sfinks   (06.01.2013 в 03:00)   письмо автору
 
   для: tvv123456   (05.01.2013 в 18:24)
 

С чего вы взяли, что для сервера самым важным будет размер файла?
У Вас больше ни с чем проблем нет?
Я ни разу не встречал проблем с размером файла скрипта. Разве что не удобно мотать вниз-вверх. Да и то современные IDE эту проблему полностью решают. Ну и к нагрузке на сервер это не имеет отношения.
Нагрузка на сервер идет от функционала, а не от размера. Можно и в 1ом килобайте зарядить рекурсивный обход дерева в MySQL и мало не покажется.
Делайте так, чтоб вам было удобно и понятно. Размер файла - это последний вопрос, который вас будет интересовать.

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования