[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: ООП для PHP
Гость_Игорь
Здравствуйте! Здесь можно вынести на оценку свой первый опыт на PHP? Если да - то как прикрепить архив?



Спустя 1 минута, 25 секунд (22.03.2011 - 21:02) sharki написал(а):
Код выкладывай =)
желательно в спойлере [spoiler ] [ /spoiler]

Спустя 6 минут, 27 секунд (22.03.2011 - 21:08) Invis1ble написал(а):
Первый опыт - и стразу ООП ?? blink.gif
Сильно... Ждем код rolleyes.gif

Спустя 4 минуты, 38 секунд (22.03.2011 - 21:13) inpost написал(а):
Или PHP для ООП? Что было первым, курица или яйцо? Не понимаю смысла этого топика, хоть убейте!

Спустя 4 минуты, 50 секунд (22.03.2011 - 21:18) Invis1ble написал(а):
Скорее, если расшифровать аббревиатуру, логичнее "ООП на PHP"... Но это так, лирическое отступление... Вобщем, ждем.

Спустя 4 минуты, 4 секунды (22.03.2011 - 21:22) Гость_Игорь написал(а):
Ок)

Скажу сразу: это первое что я написал после 1 часа чтения мануала по PHP, поэтому ясно дело куча уязвимостей, интересует мнение по поводу самого подхода (использование ООП). Всего 3 файла: index.php (страница гостевой книги), DBase.php (работа с БД), Comments.php (модуль комментариев)

Скрытый текст



<?php

/////////////////////// DBase.php ///////////////////////////////
class DBase
{
    const dbhost = "localhost";
    const dbuser = "root";         
    const dbpswd = "";           
    const dbname = "UP";
 
    private $sql;

    public function __construct()
    {
    }

 
    public function Open()
    {
        $this->sql = @mysql_connect(self::dbhost, self::dbuser, self::dbpswd);
        if (!$this->sql)
        {
            echo("<P>Ошибка подключения к серверу MySQL.</P>");
            exit();
        }
 
        if (!@mysql_select_db(self::dbname, $this->sql))
        {
            echo( "<P>Ошибка при открытии базы данных.</P>" );
            exit();
        }
 
        return $this->sql;
    }

    public function Close()
    {
        if(!mysql_close($this->sql))
        {
            echo("Не удалось завершить соединение с сервером MySQL");
        }
    }
}

?>


////////////////// Comments.php /////////////////////////
<?php

class
Comments
{
    private $sqlConnect;

    public function __construct()
    {
    }

 
    public function Open($sql)
    {
        $this->sqlConnect = $sql;
    }
 
    public function Add($Name, $Email, $Text)
    {
        $querryStr = sprintf("INSERT INTO Comments (Text) VALUES (\"%s\");", htmlspecialchars($Text));
        $querry = mysql_query($querryStr);
        if($querry)
        {
            echo "Добавлена запись.";
        }
        else
        {
            echo "Ошибка добавления значения в БД запросом ".$querryStr."<br>";
            echo mysql_error()."<br>";
        }
    }


    public function Fetch()
    {
        $querry = mysql_query("SELECT * FROM Comments;");
        if($querry)
        {
            while($rec = mysql_fetch_array($querry))
            {
                echo "<br>".$rec["Text"]."<br><br><br>";
                echo "<div style = \"width:80%;height:1px;background:#AAAAAA\"> </div>";
            }
        }

        else
        {
            echo "<p><b>Error: ".mysql_error()."</b></p>";
            exit();
        }
    }
}

?>

////////////////////////////////// index.php /////////////////////////////

<html>
<
header>
<
title>Гостевая книга</title>
</
header>

<
body>
    <
table border="0" width="100%" height="100%">
    <
tr>
    <
td width="25%"></td>
    <
td width="50%" valign="top">
    <?php

        // Загрузка комментариев
        include("DBase.php");
        include("Comments.php");
   
        $dbase = new DBase();
        $comments = new Comments();
   
        $dbase->Open();
        $comments->Open($dbase);

        // Если есть новый - добавляем
        $newComment = $_GET[AddText];
        if($newComment)
        {
            $comments->Add("Igor", "igor@mail.ru", $newComment);
     
            print "<HTML><HEAD>\n";
            print "<META HTTP-EQUIV='Refresh' CONTENT='0; URL=index.php'>\n";
            print "</HEAD></HTML>\n";
        }
     
        $comments->Fetch();
   
    ?>
    <br>
    <
br>

    <
form action = "index.php" method="get">
    <
TEXTAREA NAME="AddText" WRAP="virtual" COLS="40" ROWS="3"></TEXTAREA><br>
    <
input type="submit"/>
    </
form>
 
    </
td>
    <
td width="25%"></td>
    </
tr>
    </
table>

</
body>
</
html>




Спустя 6 минут, 31 секунда (22.03.2011 - 21:28) Invis1ble написал(а):
Сильно не вникал, но вот несколько замечаний:
1. Логика перемешана с представлением (и в классах и в "остальном" коде) - так не делается
2. Обработку ошибок лучше реализовывать посредством выброса и обработки исключений
3. mysql_fetch_array() без флага лучше не юзать, т.к. лишняя нагрузка. Или с флагом или mysq_fetch_assoc()

Спустя 4 минуты, 49 секунд (22.03.2011 - 21:33) sharki написал(а):
Гость_Игорь
Ну так, не плохо
1) Можно не прописывать пустые конструкторы, они и так пустые по дефоулту
2) В классе комментариев можно передавать как раз таки в конструктор соединение с БД т.е

....................................................
public function __construct($sql)
{
$this->sqlConnect = $sql;
}
...................................................
$comments = new Comments($sql);


3) реализация комментариев т.е их вывод из бд лучше бы отдал бы индексу.пхп чтобы отделить логику от представления

4)Ну и конечно же можно было обойтись без лишних манипуляций с БД извне т.е
public function Open($sql)
{
$this->sqlConnect = $sql;
}


Можно было бы наследовать БД класс и всё, а там уже
$this->sqlConnect = $this->sql;

Спустя 9 минут, 25 секунд (22.03.2011 - 21:43) Гость_Игорь написал(а):
Спасибо за замечания) Ну если выбранный подход имеет право на существование, буду допиливать, покажу потом что получилось)

Вообще мне показалось, что обычно в php классы как-то не особо используют. А так было бы здорово сделать framework чисто на ООП-принципах, каждый модуль (гостевая, коменнтарии, статья) - класс, отдельно классы для разных задач.

Насчет разделения логики и представления - полностью согласен, насколько мог, перетащил из index.php в классы, но как сделать еще явнее... Хотя, кажется, понял: в классах не должно встречаться ни единого echo )) А про то, что в PHP есть исключения, я не знал)

Спустя 2 минуты, 4 секунды (22.03.2011 - 21:45) sharki написал(а):
Гость_Игорь
А ты просто функцией $comments->Fetch(); возвращай тот самый массив $rec, и всё, а в индексе тупо делай fetch_assoc

Спустя 24 секунды (22.03.2011 - 21:45) inpost написал(а):
Гость_Игорь
Гугл, фейсбук, википедия написаны были на процедурке, а не ООП.

Спустя 3 минуты, 29 секунд (22.03.2011 - 21:49) Гость_Игорь написал(а):
Цитата (inpost @ 22.03.2011 - 18:45)
Гость_Игорь
Гугл, фейсбук, википедия написаны были на процедурке, а не ООП.

вот это и не понятно.. может тогда в PHP еще не появились классы?

Спустя 1 минута, 2 секунды (22.03.2011 - 21:50) Гость_Игорь написал(а):
Цитата (sharki @ 22.03.2011 - 18:45)
Гость_Игорь
А ты просто функцией $comments->Fetch(); возвращай тот самый массив $rec, и всё, а в индексе тупо делай fetch_assoc

Понял, ок)

Спустя 28 минут, 15 секунд (22.03.2011 - 22:18) inpost написал(а):
Гость_Игорь
Именно, гиганты сети сделаны на ПХП без использования ООП по той причине, что в PHP4 они ещё не существовали.

Спустя 23 минуты, 33 секунды (22.03.2011 - 22:41) alex12060 написал(а):
А еще, советую делать константы private. А еще, можно унаследовать один класс от другого, это упростит код в 10-ки раз. А функции с работой в БД так-же можно сделать приватными и открывать соединение в конструкторе.

А так, для новечка неплохо.

Спустя 21 час, 29 минут, 21 секунда (23.03.2011 - 20:11) Гость_Игорь написал(а):
Всем привет,
возникли мысли и вопросы)

1. Правильно ли я понимаю, что при выполнении php-кода страницы нужно каждый раз заново открывать соединение с MySql, открывать базу? Т.е. ВСЕ значения переменных в php живут только в рамках момента обновления страницы? Пробовал модификаторы static, global, массив $GLOBALS - не помогает, при обновлении страницы все стирается, например:


<html>
<
header>
<
title>Лаборатория</title>
</
header>
<
body>
<?php
class
Foo
{
private static $x = 0;

public function __construct()
{
$x++;
echo $x;
}
}


$foo = new Foo();

?>
</body>
</
html>


- всегда выдает 1, т.е. значение x стирается, хоть это и static. В С++ static живет пока не завершится процесс.


2. Если так, можно действительно от класса "База данных" наследовать все классы типа "Комментарии", "Статьи", "Цитаты" и пр. Подумал, что было бы удобно в каждый такой класс добавить метод с запросом CREATE TABLE, т.е. чтобы каждый раз не создавать таблицы через PhpMyAdmin (когда новая БД), запустил скрипт, который для каждого такого класса вызывает метод создания таблицы.

3. Думал как хранить меню, т.е. засунуть древовидную структуру в реляционную таблицу, чтоб число уровней вложенности не было ограниченно.
Пока пришла такая идея: каждый пункт меню - это 1 запись в таблице, есть поле "предок" и поле "потомок", где хранятся либо null, либо id другой записи в этой же таблице.

4. Можно ли вместо mysql_fetch_assoc делать mysql_fetch_object? (в смысле, что не будет ли это тормознее, просто этот способ более похож на ООП-подход).

Спустя 8 минут, 59 секунд (23.03.2011 - 20:20) inpost написал(а):
Гость_Игорь
1. В начале выполнения скрипта конектиться к БД нужно, в конце скрипта, если сам не закрыл соединение, оно автоматически закрывается, для экономии места, ведь в Мускуле есть лимит одновременных соединений, поэтому загрузил страницу, закрылось соединение, теперь через него кто-то другой обращается к БД.
2. Зачем создавать таблицу? Комментарии, статьи, цитаты хранятся в ранее созданных таблицах, каждый комментарий имеет его id, и родителя, кому он принадлежит, можно ещё добавить из какого раздела и т.д., но это как строка в Таблице, а не новая отдельная таблица.
3. Нормальная схема для неограниченного меню.
4. Нет, делай, как тебе нравится больше, ты копейку потеряешь, даже смотреть в эту сторону не надо =)

Спустя 1 час, 48 минут, 22 секунды (23.03.2011 - 22:08) Гость_Игорь написал(а):
Постарался учесть замечания) Только почему-то не получается сочетать модификаторы const и private.


///////////////// Guard.php - набор функций для защиты //////////
<?php
class
Guard
{
// Обработка пользовательского текста
static function TextProceed($text)
{
$text = stripslashes($text);
$text = htmlspecialchars($text);
return $text;
}

// Валидация e-mail'а
static function CheckEmail($email)
{
return (preg_match("/[0-9a-z_]+@[0-9a-z_^\.]+\.[a-z]{2,3}/i", $email));
}

// Проверка, что запрос произошел с нашего хоста
static function CheckHost()
{
$hostOwn = "http://";
$hostOwn.= $_SERVER["HTTP_HOST"];
$hostFrom=getenv("HTTP_REFERER");

if (!ereg($hostOwn, $hostFrom))
{
throw new Exception("Попытка взлома.");
}
}
}


?>

//////////// Table.php - базовый для всех классов-таблиц //////////
<?php
class
Table
{
private $dbhost = "localhost";
private $dbuser = "root";
private $dbpswd = "";
private $dbname = "UP";

protected $sqlConnect;

/// Открывает sql и БД
public function __construct()
{
$this->sqlConnect = @mysql_connect($this->dbhost, $this->dbuser, $this->dbpswd);
if (!$this->sqlConnect)
{
throw new Exception("Ошибка подключения к серверу MySQL.");
}
if (!@mysql_select_db($this->dbname, $this->sqlConnect))
{
throw new Exception("Ошибка при открытии базы данных." );
}
}


/// Закрывает sql
public function __destruct()
{
if(!mysql_close($this->sqlConnect))
{
throw new Exception("Не удалось завершить соединение с сервером MySQL");
}
}
}

?>

//////////////// Comments.php - работа с комментариями /////////
<?php

require_once("Table.php");
require_once("Guard.php");

class Comments extends Table
{
private $querryFetch;

public function Add($Name, $Email, $Text)
{
// Данные от формы получены с этого хоста?
Guard::CheckHost();

if (!Guard::CheckEmail($Email))
{
return;
}
$querryStr = sprintf("INSERT INTO Comments (Text) VALUES (\"%s\");", Guard::TextProceed($Text));
$querry = mysql_query($querryStr, $this->sqlConnect);
if(!$querry)
{
throw new Exception("Ошибка добавления значения в БД запросом ".$querryStr.", описание:".mysql_error());
}
// Защита от флуда
sleep(1);
}

public function BeginFetch()
{
$this->querryFetch = mysql_query("SELECT * FROM Comments;", $this->sqlConnect);
if(!$this->querryFetch)
{
throw new Exception("Ошибка выборки комментариев: ".mysql_error());
}
}


public function Fetch()
{
if($this->querryFetch)
{
return mysql_fetch_object($this->querryFetch);
}
}


public function EndFetch()
{
$this->querryFetch = null;
}
}

?>

/////////////////////////// index.php //////////////////////////////
<html>
<
header>
<
title>Гостевая книга</title>
</
header>

<
body>
<
table border="0" width="100%" height="100%">
<
tr>
<
td width="25%"></td>
<
td width="50%" valign="top">
<?php
try

{
// Загрузка комментариев
require_once("Comments.php");

$comments = new Comments();

// Если есть новый - добавляем
$newComment = $_GET[AddText];
if($newComment)
{
$comments->Add("Igor", "igor@mail.ru", $newComment);

echo "<HTML><HEAD>\n";
echo "<META HTTP-EQUIV='Refresh' CONTENT='0; URL=index.php'>\n";
echo "</HEAD></HTML>\n";
}

$comments->BeginFetch();
while($rec = $comments->Fetch())
{
echo ($rec->Text);
echo "<br>";
}
$comments->EndFetch();
}

catch(Exception $e)
{
echo 'Исключение: ' . $e->getMessage();
}
?>

<form action = "index.php" method="get">
<
TEXTAREA NAME="AddText" WRAP="virtual" COLS="40" ROWS="3"></TEXTAREA><br>
<
input type="submit"/>
</
form>
</
td>
<
td width="25%"></td>
</
tr>
</
table>

</
body>
</
html>



Спустя 4 дня, 9 часов, 52 минуты, 36 секунд (28.03.2011 - 07:01) Igorian написал(а):
Привет всем)

Прошу совета по вопросам архитектуры web-приложений.

Сделал так: архитектура сайта состоит из модулей (отображение статьи, отображение гостевой, отображение голосовалки и т.п.), каждый модуль лежит в своей папке и состоит из 3 файлов:
-view (почти чистый html)
-model (доменный объект, т.е. ООП-обертка над MySQL, например для Guestbook методы "Добавить запись", "Выбрать записи")
-controller (управляет предыдущими, т.е. обрабатывает get-запрос, дергает методы model, запускает view).

model и controller - статические классы.

Есть основное ядро сайта (как и все остальное - тоже класс). Например, юзер хочет зайти в гостевую. По get-запросу ядро понимает, что нужно активировать модуль Guestbook, оно вызывает у него метод Render, он возвращает результат работы. Используется ob_get_contens. Потом запускается файл шаблона сайта, который содержит именнованные области, например <?=main?>. Результат рендера модуля был записан в $main, а тут это все подставляется в шаблоне. Можно было бы конечно наоборот: в шаблоне дергать у логики работу модуля, но это не логично: код первичнее представления.

Как такой вариант? Особенно интересует вопрос использования ob_get_contens, нет ли там ограничений на размер результата, и насколько это нормально: рендерить скрипт не сразу на вывод, а в буфер, а потом этот буфер подставлять в шаблоне?
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.