ООП и тормоза

Lestat

Новичок
ООП и тормоза

я начинающий программист, и при изучении PHP, часто обращаюсь за консультацией.
Недавно начал разрабатывать свой небольшой универсальный движок с использованием templates и pear..

но мой "наставник" сказал мне, что бы я не использовал
все, что связано с ООП, так как это сильно тормозит работу движка..
цитирую:
"
в общем, я не вникал пока особо в код, но факт в том, что он почему-то очень тормозит
я даже могу предположить, почему...

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

1. Использование объектно-ориентированных возможностей. ПХП- на самом деле - это не объектно-ориентированный язык по своей природе. поэтому всё это очень тормозит. У нас вообще не используются объектно ориентированные возможности языка. А как по мне, так они только усложняют разработку.
2. Использование шаблонов. Я посмотрел как это реализовано
"

"Если ты обращал на это внимание, то должен был заметить, что там всё основано на механизме регулярных выражений, а это самая тормозная из всех тормозных фич.
ООП+Regular Expressions = тормоза!"

"Я же говорил, что принципиально не использую в пхп ООП потому, что пхп - это скриптовой язык, не предназначенный для ООП. ООП - это для С++ и Явы. Говорят, что в пятом есть какие-то серьёзные нововведения в этом плане..."

сейчас он меня убедил отказаться от пеар, ООП, использовать только класс DB, и все..

что скажете?

ну и на всякий кину класс шаблонов

PHP:
class XTemplate {

var $filecontents="";								/* raw contents of template file */
var $blocks=array();								/* unparsed blocks */
var $parsed_blocks=array();					/* parsed blocks */
var $block_parse_order=array();			/* block parsing order for recursive parsing (sometimes reverse:) */
var $sub_blocks=array();						/* store sub-block names for fast resetting */
var $VARS=array();									/* variables array */

var $file_delim="/\{FILE\s*\"([^\"]+)\"\s*\}/m";  /* regexp for file includes */
var $block_start_delim="<!-- ";			/* block start delimiter */
var $block_end_delim="-->";					/* block end delimiter */
var $block_start_word="BEGIN:";			/* block start word */
var $block_end_word="END:";					/* block end word */

/* this makes the delimiters look like: <!-- BEGIN: block_name --> if you use my syntax. */

var $NULL_STRING=array(""=>"");				/* null string for unassigned vars */
var $NULL_BLOCK=array(""=>"");	/* null string for unassigned blocks */
var $mainblock="";
var $ERROR="";
var $AUTORESET=1;										/* auto-reset sub blocks */

/***[ constructor ]*********************************************************/

function XTemplate ($file,$mainblock="main") {
	$this->mainblock=$mainblock;
	$this->filecontents=$this->r_getfile($file);	/* read in template file */
	$this->blocks=$this->maketree($this->filecontents,$mainblock);	/* preprocess some stuff */
	$this->scan_globals();
}


/***************************************************************************/
/***[ public stuff ]********************************************************/
/***************************************************************************/

/***[ assign ]**************************************************************/
function assign ($name,$val="") {
	if (gettype($name)=="array")
		while (list($k,$v)=each($name))
			$this->VARS[$k]=$v;
	else
		$this->VARS[$name]=$val;
}

/***[ parse ]***************************************************************/
function parse ($bname) {
	$copy=$this->blocks[$bname];
	if (!isset($this->blocks[$bname]))
		$this->set_error ("parse: blockname [$bname] does not exist");
	preg_match_all("/\{([A-Za-z0-9\._]+?)}/",$this->blocks[$bname],$var_array);
	$var_array=$var_array[1];
	while (list($k,$v)=each($var_array)) {
		$sub=explode(".",$v);
		if ($sub[0]=="_BLOCK_") {
			unset($sub[0]);
			$bname2=implode(".",$sub);
			@$var=$this->parsed_blocks[$bname2];
			$nul=(!isset($this->NULL_BLOCK[$bname2])) ? $this->NULL_BLOCK[""] : $this->NULL_BLOCK[$bname2];
			$var=(empty($var))?$nul:trim($var);
			$copy=preg_replace("/\{".$v."\}/","$var",$copy);
		} else {
			$var=$this->VARS;
			while(list($k1,$v1)=each($sub))
				$var=$var[$v1];
			$nul=(!isset($this->NULL_STRING[$v])) ? ($this->NULL_STRING[""]) : ($this->NULL_STRING[$v]);
			$var=(!isset($var))?$nul:$var;
			$copy=preg_replace("/\{$v\}/","$var",$copy);
		}
	} 	
	$this->parsed_blocks[$bname].=$copy;
	// reset sub-blocks 
	if ($this->AUTORESET && (!empty($this->sub_blocks[$bname]))) {
		reset($this->sub_blocks[$bname]);
		while (list($k,$v)=each($this->sub_blocks[$bname]))
			$this->reset($v);
	}
}

/***[ rparse ]**************************************************************/
/*
	returns the parsed text for a block, including all sub-blocks.
*/

function rparse($bname) {
	if (!empty($this->sub_blocks[$bname])) {
		reset($this->sub_blocks[$bname]);
		while (list($k,$v)=each($this->sub_blocks[$bname]))
			if (!empty($v)) 
				$this->rparse($v,$indent."\t");
	}
	$this->parse($bname);
}

/***[ insert_loop ]*********************************************************/
/*
	inserts a loop ( call assign & parse )
*/

function insert_loop($bname,$var,$value="") {
	$this->assign($var,$value);		
	$this->parse($bname);
}

/***[ text ]****************************************************************/
/*
	returns the parsed text for a block
*/

function text($bname) {
	return $this->parsed_blocks[isset($bname) ? $bname :$this->mainblock];
}

/***[ out ]*****************************************************************/
/*
	prints the parsed text
*/

function out ($bname) {
	echo $this->text($bname);
}

/***[ reset ]***************************************************************/
/*
	resets the parsed text
*/

function reset ($bname) {
	$this->parsed_blocks[$bname]="";
}

/***[ parsed ]**************************************************************/
/*
	returns true if block was parsed, false if not
*/

function parsed ($bname) {
	return (!empty($this->parsed_blocks[$bname]));
}

/***[ SetNullString ]*******************************************************/
/*
	sets the string to replace in case the var was not assigned
*/

function SetNullString($str,$varname="") {
	$this->NULL_STRING[$varname]=$str;
}

/***[ SetNullBlock ]********************************************************/
/*
	sets the string to replace in case the block was not parsed
*/

function SetNullBlock($str,$bname="") {
	$this->NULL_BLOCK[$bname]=$str;
}

/***[ set_autoreset ]*******************************************************/
/*
	sets AUTORESET to 1. (default is 1)
	if set to 1, parse() automatically resets the parsed blocks' sub blocks
	(for multiple level blocks)
*/

function set_autoreset() {
	$this->AUTORESET=1;
}

/***[ clear_autoreset ]*****************************************************/
/*
	sets AUTORESET to 0. (default is 1)
	if set to 1, parse() automatically resets the parsed blocks' sub blocks
	(for multiple level blocks)
*/

function clear_autoreset() {
	$this->AUTORESET=0;
}

/***[ scan_globals ]********************************************************/
/*
	scans global variables
*/

function scan_globals() {
	reset($GLOBALS);
	while (list($k,$v)=each($GLOBALS))
		$GLOB[$k]=$v;
	$this->assign("PHP",$GLOB);	/* access global variables as {PHP.HTTP_HOST} in your template! */
}

/******

		WARNING
		PUBLIC FUNCTIONS BELOW THIS LINE DIDN'T GET TESTED

******/


/***************************************************************************/
/***[ private stuff ]*******************************************************/
/***************************************************************************/

/***[ maketree ]************************************************************/
/*
	generates the array containing to-be-parsed stuff:
  $blocks["main"],$blocks["main.table"],$blocks["main.table.row"], etc.
	also builds the reverse parse order.
*/


function maketree($con,$block) {
	$con2=explode($this->block_start_delim,$con);
	$level=0;
	$block_names=array();
	$blocks=array();
	reset($con2);
	while(list($k,$v)=each($con2)) {
		$patt="($this->block_start_word|$this->block_end_word)\s*(\w+)\s*$this->block_end_delim(.*)";
		if (preg_match_all("/$patt/ims",$v,$res, PREG_SET_ORDER)) {
			// $res[0][1] = BEGIN or END
			// $res[0][2] = block name
			// $res[0][3] = kinda content
			if ($res[0][1]==$this->block_start_word) {
				$parent_name=implode(".",$block_names);
				$block_names[++$level]=$res[0][2];							/* add one level - array("main","table","row")*/
				$cur_block_name=implode(".",$block_names);	/* make block name (main.table.row) */
				$this->block_parse_order[]=$cur_block_name;	/* build block parsing order (reverse) */
				@$blocks[$cur_block_name].=$res[0][3];					/* add contents */
				$blocks[$parent_name].="{_BLOCK_.$cur_block_name}";	/* add {_BLOCK_.blockname} string to parent block */
				$this->sub_blocks[$parent_name][]=$cur_block_name;		/* store sub block names for autoresetting and recursive parsing */
				$this->sub_blocks[$cur_block_name][]="";		/* store sub block names for autoresetting */
			} else if ($res[0][1]==$this->block_end_word) {
				unset($block_names[$level--]);
				$parent_name=implode(".",$block_names);
				$blocks[$parent_name].=$res[0][3];	/* add rest of block to parent block */
  			}
		} else { /* no block delimiters found */
			@$blocks[implode(".",$block_names)].=$this->block_start_delim.$v;
		}
	}
	return $blocks;	
}



/***[ error stuff ]*********************************************************/
/*
	sets and gets error
*/

function get_error()	{
	return ($this->ERROR=="")?0:$this->ERROR;
}


function set_error($str)	{
	$this->ERROR=$str;
}

/***[ getfile ]*************************************************************/
/*
	returns the contents of a file
*/

function getfile($file) {	
	if (!isset($file)) {
		$this->set_error("!isset file name!");
		return "";
	}

	if (is_file($file)) {
		if (!($fh=fopen($file,"r"))) {
			$this->set_error("Cannot open file: $file");
			return "";
		}

		$file_text=fread($fh,filesize($file));
		fclose($fh);
	} else { 
		$this->set_error("[$file] does not exist");
		$file_text="<b>__Фатальная ошибка: файл [$file] не существует __</b>";
	}
		
	return $file_text;
}

/***[ r_getfile ]***********************************************************/
/*
	recursively gets the content of a file with {FILE "filename.tpl"} directives
*/


function r_getfile($file) {
	$text=$this->getfile($file);
	while (preg_match($this->file_delim,$text,$res)) {
		$text2=$this->getfile($res[1]);
		$text=preg_replace("'".preg_quote($res[0])."'",$text2,$text);
	}
	return $text;
}

} /* end of XTemplate class. */
 

SiMM

Новичок
Я бы сказал - менять наставника. Уж больно "убедительные" он приводит аргументы ;) Медленную программу можно написать с использованием любой идеологии, а говорить безапелляционно, что PCRE - большие тормоза из всех тормозов - это с головой надо недружить - да, они могут оказаться медленнее, чем строковые аналоги, но случаи то разные бывают - у тебя, похоже, большой необходимости в них нет, по крайней мере - не везде (говорю это лишь мельком глянув на исходник).
 

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
Re: ООП и тормоза

Автор оригинала: Lestat
что скажете?
1. "наставника" гнать в шею.
2. шаблонный движок либо выкинуть, либо добавить кэширование. Если разбирать шаблоны рег. выражениями на каждой загрузке, тормозить будет.
3. использовать bytecode cache
 

svetasmirnova

маленький монстрик
Результаты benchmark тестов на WinXP SP1 (cli):
PHP4:
Just function run: 0.006505
Once class creation and its method calling: 0.006558
Static class method calling: 0.006533
Method calling (instance): 0.008254
PHP5:
Just function run: 0.017830
Once class creation and its method calling: 0.008226
Static class method calling: 0.008167
Method calling (instance): 0.007709
Исходник теста (использует пакет PEAR_Benchmark):
PHP:
function a($amount = 10) {
    for ($i=0; $i < $amount; $i++) {
        for ($i=0; $i < 100; $i++);
    }
}

class B {
    function a($amount = 10) {
        for ($i=0; $i < $amount; $i++) {
            for ($i=0; $i < 100; $i++);
        }
    }
}
require_once 'Benchmark/Timer.php';
$timer = new Benchmark_Timer();
$timer->start();
$timer->setMarker('Mark0');
for ($i=0; $i < 100; $i++) a(100);
$timer->setMarker('Mark1');
$b = new B;
for ($i=0; $i < 100; $i++) $b->a(100);
$timer->setMarker('Mark2');
for ($i=0; $i < 100; $i++) B::a(100);
$timer->setMarker('Mark3');
for ($i=0; $i < 100; $i++) $b->a(100);
$timer->setMarker('Mark4');
echo "Just function run: " .
      $timer->timeElapsed('Mark0', 'Mark1') . "\n";
echo "Once class creation and its method calling: " .
      $timer->timeElapsed('Mark1', 'Mark2') . "\n";
echo "Static class method calling: " .
      $timer->timeElapsed('Mark2', 'Mark3') . "\n";
echo "Method calling (instance): " .
      $timer->timeElapsed('Mark3', 'Mark4') . "\n";
$timer->stop();
P.S.: Интересно сравнить результаты на разных ОС, хотя ответ на вопрос Lestat, я думаю, будет таким же.

А про наставника даже ничего говорить не буду:D
 

Demiurg

Guest
ооп - это в первую очередь срадство проектирования, а не кодирования.
 

svetasmirnova

маленький монстрик
Originally posted by Demiurg
ооп - это в первую очередь срадство проектирования, а не кодирования.
Но тормозит или нет можно посчитать;)

Кстати, в моём примере PHP4.3.3 и PHP5.1.0-dev

Lestat
А скорость работы регулярных выражений надо в каждом конкретном случае смотреть
 

Demiurg

Guest
>Но тормозит или нет можно посчитать
так же можно сравнить популяцию тараканов и людий и на этих основаниях выводить кто главнее.
 

Buteo

[CDR/DVP]
Renny а посмотреть инфо об авторе трудно?
День рождения: July 12, 1985 -- но это оффтоп
 

svetasmirnova

маленький монстрик
Originally posted by Demiurg
>Но тормозит или нет можно посчитать
так же можно сравнить популяцию тараканов и людий и на этих основаниях выводить кто главнее.
А кто такие выводы делает?

Меня просто раздражают встречающиеся по жизни "наставники", которым лень проверить свои категорические утверждения.

Тест я написала, когда засомневалась в использовании ООП "по жизни". Например, бывает такой выбор: для чего-то очень простого написать функцию или метод класса. Метод класса мне удобнее, но я не хочу к старости в этакого "наставника" превратится ;)

Также полезным бывает узнать производительность, в том числе для чисто стилистических вещей. Например, ещё забавный тест PHP4 vs PHP5 - что быстрее:
PHP:
$str = 'Hello, ' . $name;
или
$str = "Hello, $name";
В конце концов, чисто стилистическая привычка писать 0 == $x вместо $x == 0 экономит минуты, часы...

Renny
Мне встречались люди "за 40" с подобными вопросами. Только они потом почему-то всё равно самостоятельных выводов не делали:mad:
 

wrapper

Guest
Автор оригинала: Demiurg
ооп - это в первую очередь срадство проектирования, а не кодирования.
Что значит сия мысль? Проектировать в терминах обьектов а писать процедурный код?
 

Crazy

Developer
wrapper, сия мысль означает, что проектировать нужно в терминах объектов и, если это возможно, так же и программировать. Что, однако, не исключает сочетания объектно-ориентированного проектирования и процедурного программирования.

Тогда как мы зачастую наблюдает уродливую объектную реализацию, созданную поверх процедурной модели.
 

Demiurg

Guest
svetasmirnova
Код:
$str = 'Hello, ' . $name; 
или 
$str = "Hello, $name";
это именно способ кодирования, и сравнивать скорость тут уместно. Судя по твоим ответам в форуме, ты хорошо представляешь себе плюсы и минусы ОО-подхода. Но вот для новичков приведение цифр без объяснения всего другого может оказаться руководством к действию.
 

svetasmirnova

маленький монстрик
Demiurg
Автор оригинала: Lestat
>но мой "наставник" сказал мне, что бы я не использовал
>все, что связано с ООП, так как это сильно тормозит работу движка..
А я не привыкла необоснованно что-то утверждать.

Новички!
Мои посты - не руководство к действию, а информация к размышлению :)
Автор оригинала: SiMM
Медленную программу можно написать с использованием любой идеологии
Кстати, хорошие книжки по ООП содержат описание недостатков этого подхода.

По поводу PEAR в листе PEAR-general в конце октября - начале ноября была дискуссия как раз по теме: стоит ли использовать? Правда, там человек больше беспокоился о безопасности. Тоже можно посмотреть.
 

Screjet

Новичок
Я бы сказал "ООП = это путь к прогрессу и процветанию" (по опыту).
1,5 года назад, когда только попал на этот форум, задавал такие же идиотские вопросы, типа "что быстрее".
А сейчас есть собственная библиотека разработок, которые использую как компоненты для еще не написанных проектов.
(сорри за философию)

Если твой наставник настолько противник ООПа, меняй наставника :)
 

Demiurg

Guest
>ООП = это путь к прогрессу и процветанию
маркетингом заниматься не пробовал ?
 

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
На мой взгляд проще разбить проект на классы, чтобы в будущем обеспечить переносимость кода (если нужно). Мне писать что-либо, используя одни функции неудобно, так как привык к использованию классов. Конечно можете кричать на меня, но если "наставник" так уверенно говорит что тормозит а что нет, я бы в первую очередь его слова проверил :)
 

Lestat

Новичок
я проверил....
движок с использованием класса xtpl генерируеться за 0.068..
после того, как я отказался от него и перенес все шаблоны в функции, скрипт стал работать быстрее: 0.039
разница ощутимая помоему

а кодить я только начинаю... у меня очень мало опыта.. все приходит со временем
 
Сверху