BG translation
[email protected] (Ivaylo Botyov Nikolov) Sat, 21 Apr 2007 15:04:04 +0200
| Newsgroups | php.gtk.doc |
|---|---|
| Organization | Divoto |
| Message-ID | <[email protected]> |
New translated file in Bulgarian language. More to come after few days. Ivaylo Botyov Nikolov DIVOTO Via Alcione 11 Anzio 00042, (RM) www.divoto.net email: [email protected] Tel: +39 06.60513507 Mob: +39 329.3210034
objectorientation.xml
(application/xml, 26.7 KB)
<?xml version="1.0" encoding="utf-8" ?>
<!-- $Revision: 1.5 $ -->
<chapter id="tutorials.objectorientation">
<title>Обектно-Ориентирано Програмиране</title>
<sect1>
<title>Отностно този урок</title>
<simpara>
В този урок ще се опитаме да ви научим обектно-ориентираното програмиране в
PHP-GTK 2. Поддръжката на обектно-оринтираното програмиране в PHP5 е вече
много голяма и при писане на програми под PHP-GTK 2 можем да се вазползваме
от всичките тях.
</simpara>
<simpara>
Защо е модерно да се използва обектно-ориентираното програмиране? Има
много предимства при използването на този стил на програмиране, особено
ако вашата програма е разделена на няколко модула и се очаква да бъде
хиляди редове. Основното преимущество, е че се получава изчистен и добре
организиран код. Ще е много по-лесно за вас или другите да прочетете или
модифицирате кода на програмата ако той е написан чрез използване на
обектно-ориентираният стил отколкото стандартният процедурен начин.
</simpara>
<simpara>
Ако ссте убедени, че обектно-ориентираният начин, е вашият начина да
програмирате нека продължим по-нататък!
</simpara>
</sect1>
<sect1 id="tutorials.objectorientation.basics">
<title>Основи при обектното-ориентирано програмиране</title>
<simpara>
Предполага се, че сте запознати с основата на обектно-ориентираното
програмиране. Ако не сте, е желателно първо да се запознаете преди да
продължите с този урок. Също така, можете да се запознаете с ръководството
на PHP5 с частта, разглеждаща обектно-ориентираното програмиране, за да
придобиете по-голяма представа за същността на този метод.
</simpara>
<para>
Нека да започнем с "пренасянето" на простият пример Hello World! и
пренаписване на тази програма използвайки обектно-ориентираното
програмиране, за да навлезете в същността по-бързо. Първото нещо, което
трябва да направите е клас. Най-лесният начин за това е да разширите някой
от класовете на PHP-GTK 2. В повечето класове първият уйджет, който ще
срещнете е <classname>GtkWindow</classname>. Така ще направим и в нащата
програма Hello World. Това, което ще направим е да създадем клас, който
<literal>разширява (extends)</literal> <classname>GtkWindow</classname>,
за да ни е по-лесна работата:
<programlisting role="php"><![CDATA[
<?php
class Hello extends GtkWindow
{
// тук е нашият код.
}
?>]]></programlisting>
Сега е необходимо да създадем конструктор на нашият клас (функция, която
се извиква, когато обект в нашият клас се съдава). Нека сега да помислим
какво ни е необходимо да сложим в този конструктор. Тъй като конструкторът
е първото нещо, което се извиква, когато обект от нашият клас се създава,
е необходимо да поставим всичко, което има връзка с дезайнът в нашият
конструктор. От това следва, че конструкторът е мястото, където всичките
ни необходими уйджети ще бъдат създадени, проектираме тяхното разполагане
(виж <link linkend="tutorials.packing">Пакетиране на Уйджети</link>) и
най-накрая, как ще изглежда нашата програма.
</para>
<para>
Сега нашият клас разширява <classname>GtkWindow</classname>, но това не
означава, че конструктурът на <classname>GtkWindow</classname> се извиква
автоматично. Това е основното поведение при PHP5 и извикването на
конструктура <classname>GtkWindow</classname> става единствено чрез
ключовата дума <literal>parent</literal>:
<programlisting role="php"><![CDATA[
class Hello extends GtkWindow
{
function __construct()
{
parent::__construct();
}
}
]]></programlisting>
Това означава, че GtkWindow ще бъде създаден (без никакви параметри,
изпратени към конструктура) винаги, когато обектът от нашият клас "Hello"
е създаден. Възниква въпроса обаче как да достигнем до току що създаденият
прозорец. Идва ни на помощ ключоната дума <literal>this</literal>!
Използвайки тази ключова дума можем да променяме аспектите на нашият
новосъздаден прозорец:
<programlisting role="php"><![CDATA[
function __construct()
{
parent::__construct();
$this->set_title('Hello World!');
$this->connect_simple('destroy', array('gtk', 'main_quit'));
}
]]></programlisting>
</para>
<para>
Тъй като това е много проста програма можем да извършим всички наши
операции директно в конструктура. Поставяме нашият код както при
процедурното програмиране директно в конструктора. И така програмата
ни ще изглежда по този начин:
<example>
<title>Hello World - Обектно-ориентиран стил на програмиране</title>
<programlisting role="php">
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
href="&directory.examples;/tutorials/objectoriented/simple.phpw" parse="text">
<xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
</xi:include>
</programlisting>
</example>
Въпреки, че това не е примерът, с който можете да разберете начините на
обектно-ориентираното програмиране е една отправна точка за всеки в
началото. Сега нека разгледаме по-сложен пример.
</para>
</sect1>
<sect1 id="tutorials.objectorientation.advanced">
<title>С по-голяма сложност</title>
<para>
До сега не използвахме обектно-ориентираните способности на PHP5. Нека да
направим една програма, която ще отвори текстов файл и ви показва
съдържанието му - опростен вариант на notepad. Имайте в предвид, че това е
една наистина много проста програма, която се използва за целите на
обучението и няма практическа приложимост! Ето ви и кода на програмата.
Прочетете го, но да не се разучаровате от размерът му. По-подробни
обяснения следват след кода:
<example>
<title>A simple notepad</title>
<programlisting role="php">
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude"
href="&directory.examples;/tutorials/objectoriented/notepad.phpw" parse="text">
<xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
</xi:include>
</programlisting>
</example>
</para>
<sect2 id="tutorials.objectorientation.advanced.construct">
<title>Конструктурът</title>
<para>
Структурата на класа е подобна на тази, която разгледахме преди. Разликата
е в присъствието на някой свойства на класове и функции. Нека първоначално
да разгледаме конструктура. Конструктрурът приема единственият аргумент
<literal>null</literal>. Този параметър е (пътеката) на файлът, който
искаме да отворим. Ако не подадете параметър към конструктура ще бъде
отворен празен файл.
</para>
<para>
И така, първо създаваме основата чрез GtkWindow и след това създавме
уйджетите, които ще използваме. Използваме <classname>GtkVBox</classname>
за разполагането на елементите, <classname>GtkTextBuffer</classname> и
<classname>GtkTextView</classname>, за да покажем съдържанието на файла и
<classname>GtkStatusBar</classname> за допълнителни съобщения. Създаваме
интерфийсът и добавяме необходимите уйджети към VBox.
</para>
<para>
Следващата стъпка е да зададем свойствата на класа:
<programlisting role="php"><![CDATA[
$this->currentFile = $fileName;
$this->buffer = $textBuff;
$this->status = $statusBar;
]]> </programlisting>
С тези три линии създавеме свойствата на класа. Свойствата на класа са
основната част при обектно-ориентираното програмирането при PHP-GTK 2.
Използването им е моного полезно, за да можем да използваме уйджет от
функция, за която не е била създадена. При създаване на уйджет
предназначението на обекта е само във функцията, която го е създала. Ето
ви един пример: Създаваме лента за състояние в конструктура на нашият клас,
но със сигурност ще трябва да имам достъп до него и от други места,
например, за да добавим някакво съобщение. Но тъй като променливата
<literal>$statusBar</literal> е достъпна само от конструктураca, просто
добавяме към него свойството на класа, наречено <literal>status</literal>.
Вече можем да имаме достъп до лентата за състоянието от която и да е
функция в класа, чрез използване на <literal>$this->status</literal>.
</para>
<para>
Просто разширете тази концепция и за други уйджети. Добавете свойтва на
класа в уйджета, който мислите, че ще бъде използван в целият клас.
Всъщност, свойствата на класа могат ефективно да се използват за
съхраняване на данни, които ще са ви необходими в целият клас. Един пример
за това в нашата програма е стойността на <literal>currentFile</literal>.
Просте ще бъде запазен пътя на отвореният файл или <literal>null</literal>
(нищо) ако няма такъв. По този начин можем да намерим името на файлът
отворен в момента, с която и да е функция в даденият клас. Свойството на
класа има и други приложения. Едно от тях е използването му като знаме.
За нашата програма за тектово редактиране може би ще желаете да добавите
стойност на класа наречен <literal>saved</literal>, която ще показва, дали
даденият файл е бил запазен на диска ни.
</para>
<para>
Забележете, че всичките стойности на класа са декларирани като
<literal>protected</literal> (защитени). Това е една много добра практика
при обектно-ориентираното програмиране. Ние не искаме те да са публично
достояние, но в същото време искаме и всеки клас, който разширява този клас
да има достъп до тези данни.
</para>
<para>
За карй добавяме име на прозорец, максимизираме го, добавяме интерфеисът и
показваме всички уйджети. След това извикваме функцията
<literal>loadFile()</literal>, за да покажем съдържанието на нашият файл
от буферът, който създадохме преди.
</para>
</sect2>
<sect2 id="tutorials.objectorientation.advanced.buildmenu">
<title>Функцията buildMenu()</title>
<para>
Забележете, че тази функция се извиква от конструктура:
<programlisting role="php"><![CDATA[
$mainBox->pack_start($this->buildMenu(), false, false);
]]> </programlisting>
Това правим, защотото искаме да разделим нашият клас на колкото е
възможно повече модули. Вместо да изградим целият интерфейс вътре в
конструктура е по-добре да го разделим на основни части и да създадем
функции за всяка една от тези части. Тук имаме функция за създаване на
лента с меню, изключващи прозореца за преглед на текста и лентата за
състоянието, което се прави с по 2 реда за всяка една от тях!
</para>
<para>
В тази функция просто създаваме лента с меню, добавяме меню за файловете
със единственото съдържание "Quit" (Изход) бутон. Нека да погледенм
следният код:
<programlisting role="php"><![CDATA[
$quit->connect_simple('activate', array($this, 'quit'));
$quit->connect_simple('enter_notify_event', array($this, 'updateStatus'), 1);
$quit->connect_simple('leave_notify_event', array($this, 'updateStatus'), 0);
]]> </programlisting>
Тук свързваме <literal>activate</literal>,
<literal>enter-notify-event</literal> и
<literal>leave-notify-event</literal> към изпълнителните функции.
Разгледайте вторият параметър на функцията
<literal>connect_simple()</literal>. Това е масив с два елемента. Първият
ебемент е специалната променлива <literal>$this</literal>, а вторият е низ.
Ако вече сте прочели урокът за
<link linkend="tutorials.helloworld">Hello World (Здравей свят)</link> сте
се натъкнали на това:
<programlisting role="php"><![CDATA[
$wnd->connect_simple('destroy', array('gtk', 'main_quit'));
]]> </programlisting>
Разгледайте това използване и ше видите, че винаги когато се опитвате да
свържете сигнала със възвратна функция, която се намира в клас, трябва
да зададете обратно повикване като масив, първият от елементите да е
пътят към функцията, а вторият елемент е името на завръщането. Свързваме
различни събития с бутона ни за изход с класовете на <literal>this</literal>
- <literal>quit()</literal> и <literal>updateStatus()</literal> функциите.
</para>
<para>
Понякога е възможно да предадете параметри на , за да може да бъдат
използвани тези обекти във функцията. Ако имате повече от една функция,
която използва даден обект е по-добре за него да създадете специфичен
параметър на класа. Ако имате само една функция, която използва този обект
е по-добре да предадете обекта като параметър. Това е често използвано в
ситуациите, когато свързвате сигналите с възвратните функции. За повече
информация вижте урока за сигналите и възвратните функции и за това, как
да предадете свободно избран параметър към възвратниту функции.
</para>
<para>
Връщането назад към функцията става чрез добавяне на уйджета
<literal>top-most</literal> в нашето меню. В лентата за меню добавяме под
меню. Конструктура взема този обект и го добавя към главният VBox.
</para>
</sect2>
<sect2 id="tutorials.objectorientation.advanced.loadfile">
<title>Функцията loadFile()</title>
<para>
Задачата на тази функция е да зареди съдържанието на файла, който искаме
да обработим и да го покаже в текстовия прозорец. Първото нещо, което
трябва да направим е да проверим дали параметъра на класа
<literal>currentFile</literal> не е празен (null) и ако не, използваме
функцията <function class="GtkTextBuffer">set_text</function>, за да покаже
съдържанито на класа от <literal>buffer (буфера)</literal>.
</para>
</sect2>
<sect2 id="tutorials.objectorientation.advanced.updatestatus">
<title>Функцията updateStatus()</title>
<para>
Тази функция служи като възвратна функция за сигналите
<literal>enter-notify-event</literal> и
<literal>leave-notify-event</literal>. Достъпът до лентата до състоянието
става чрез стойността на класа <literal>status</literal> и добавяне/махане
на съобщение в зависимост, дали мишката отива върху бутона за изход или се
отдалечава от него.
</para>
</sect2>
<sect2 id="tutorials.objectorientation.advanced.quit">
<title>Функциятя quit()</title>
<para>
Това е най-елементарната от всички функции. Сигналът, който спира главният
цикъл на GTK. Питате се, защо ни е необходима тази едноредова функция,
наречена 'quit', когато можем да свържем сигналите директно към
<literal>main_quit</literal> по този начин:
<programlisting role="php"><![CDATA[
$this->connect_simple('destroy', array('Gtk', 'main_quit'));
]]> </programlisting>
Причината за това е в самата програма. Почти сигурно е, че преди излизане
от програмата да искаме да освободим ресурсите и буферите, изполвани от
програмата и точно това прави тази функция. При нашият пример с програмата
за текстообработка бихме искали да направим проверка на маркера
<literal>saved</literal> (още веднъж стойност на класа) и да покажем диалог
за запазване на файла ако той не е бил запазен.
</para>
</sect2>
<sect2 id="tutorials.objectorientation.advanced.instantiate">
<para>
Последните два реда:
<programlisting role="php"><![CDATA[
new Notepad('simple.phpw');
Gtk::main();
]]> </programlisting>
създават обект в нашият клас (и отваря файлът simple.phpw, намиращ се в
същата директория) и започва главният цикъл на GTK. Можете да преместите
<literal>Gtk::main()</literal> в конструктура на нашият клас.
</para>
</sect2>
</sect1>
<sect1 id="tutorials.objectorientation.summary">
<title>Обобщение</title>
<para>
Надявям се този урок ви е бил от полза, за да можете да се запознаете с
обектно-ориентираното програмиране в PHP-GTK 2. Преди да завършим този урок
нека ви дам последни напътствия, които да следвате.</para>
<para>
<itemizedlist>
<listitem>
Ако създавате много голяма и сложна програма, може би е по-добре да я
разделите на одтелни класове: по един клас за всеки модул. В повечето
програми един клас ще е достатъчен.
</listitem>
<listitem>
Ако използвате много класове във вашата програма възниква въпросът с
достъпът до обектите от другите класове. В този случай, е най-удобно да
създадете йерархия на класовете: един главен клас с други класове, които
го разширяват.Ако това не е възможно можете да използвате глобалните
променливи, но не ви го препоръчваме.
</listitem>
<listitem>
Ако повече от една функция във вашият клас трябва да има достъп до
определен уйджет, направете го свойство на класа. Ако обаче само една
функция има нужда от този уйджет го предайте като параметър.
</listitem>
<listitem>
Винаги се опитвайте да разширите вашите класове от уйджет класа, който ще
Always формира основата на вашият клас. също така, не забравайте, че
трябва дза създадете уйджета чрез изполване на
<literal>parent::__construct();</literal>. Можете да имате достъп до тези
методи на уйджета чрез изполване на <literal>this</literal>.
</listitem>
<listitem>
Пишете колкото се може по-кратки функции. Цялата идея на
обектно-ориентираното програмиране е използването на модули. Ако функцията
ви стане голяма - опитайте се да я разделите. Това най-често се получава,
когато се опитвате да създадете интерфейсът на програмата си в самият
конструктор. Вместо това разделете тази голяма функция на по-малки функции
които създават части от вашият интерфейс и след това ги сглобете в
конструктура.
</listitem>
</itemizedlist>
</para>
<para>
Не забравяйте да погледнете в разделът Gtk2_Components на
<ulink url="http://pear.php.net/">PEAR</ulink>.
Всички пакети там са написани чрез използване на обектно-ориентирано
програмиране на високо ниво. Разгледайте тяхното съдържание и се опитайте да
подражавате на стила им. Успех!
</para>
</sect1>
</chapter>