Řízené vkládání zdrojových kódů
07. 03. 2003 | Ondřej Jureček | PHP | Komentáře: 0
Čím větší projekt, tím je implementace složitější. Je potřeba komunikovat s databázovým serverem, FTP, IMAP, zpracovávat XML a jiné vstupy. V tomto článku se budu zabývat otázkou, jak správně a přehledně řídit zařazování kódu v rozsáhlém PHP skriptu. Využiji přitom metodu objektového programování, kdy vývojář píše jednotlivé komponenty a udržuje si pořádek stylem "co objekt, to samostatný soubor".
Máme-li určen cíl, pojďme si hned ukázat techniku, jak řídit řazení PHP kódu v programu. Já osobně v PHP programuji objektově. Každý objekt píši do vlastního souboru, udržuji ho pak v určeném adresáři. Uvažujme o hlavním skriptu index.php. Chci-li vytvořit objekt A (instanci třídy A), musí interpret PHP znát jeho definici třídy. Pak bych mohl psát:
<?php
$A = new class_a();
?>
Definici třídy class_a() uloženou v souboru class_a.php, musím načíst jedním z příkazů:
<?php
include 'class_a.php';
require 'class_a.php';
include_once 'class_a.php';
require_once 'class_a.php';
?>
Rozdíl mezi těmito příklady je dostatečně popsán v manuálu PHP. Nyní se pojďme podívat, jak by vypadal kód programu, pokud bychom používali více objektů:
<?php
// index.php
require_once 'class_a.php';
require_once 'class_b.php';
$a = new class_a();
$b = new class_b();
?>
<?php
// class_a.php
require_once 'class_c.php';
class a {
...
}
?>
V tomto jednoduchém příkladu potřebujeme pracovat s objekty A a B. Objekt A ještě pro svou práci využívá objekt C. Říkáme tedy, že funkčnost objektu A je závislá na objektu C. Tento příklad je přehledný, v adresáři existují vedle souboru index.php i class_a.php, class_b.php a class_c.php. Soubor index.php může být v tomto případě výchozím dokumentem webu, ovšem proč v tomto adresáři vedle něj existují class_a.php, class_b.php a další? Tyto soubory by měly patřit mimo část _public_ našeho webu. Přesuňme je tedy mimo tuto oblast a podívejme se na kód příkladu nyní:
<?php
// index.php
require_once '../../../htprivate/code/class_a.php';
require_once '../../../htprivate/code/class_b.php';
$a = new class_a();
$b = new class_b();
?>
<?php
// class_a.php
require_once '../../../htprivate/code/class_c.php';
class a {
...
}
?>
Jak dlouho by nám asi trvalo vyznat se po týdnu v tomto kódu a jak dlouho by to mohlo trvat u rozsáhlého skriptu? Vyvíjíme přece webovou aplikaci, každou chvíli se něco mění a ačkoli máme připravenu analýzu, musíme občas přepisovat kód, který jsme napsali již před dvěma měsíci... Pak se v takových odkazech na soubory těžko orientujeme a odvádíme pozornost jinam. U většího projektu určitě stojí za to situaci řešit. Princip mého řešení je blízký pointrům z C. Nebudu při každé potřebě určitého kódu psát:
<?php
include 'cesta/jmenosouboru.php'
?>
Raději se vždy odkáži na funkci, která to zařídí:
<?php
// index.php
require_once '../../../htprivate/project/code/setup.php';
load_a();
load_b();
$a = new class_a();
$b = new class_b();
?>
<?php
// class_a.php
load_c();
class a {
...
}
?>
Nevolám už require_once() (na začátku skriptu ručně načtu jen setup.php), ale volám "načti třídu A!", "načti třídu B!". V programu potřebuji načíst deklaraci tříd a je mi na tomto místě přece jedno, odkud (z jakého souboru) se třída A (respektive třída B) načte. Obě funkce využívají objekt CODE MANAGERA:
<?php
class code_manager {
var $DIRECTORY_ROOT = '';
function code_manager($root = NULL) {
if (isset($root)):
$this->set_dirroot($root);
endif;
}
function set_dirroot($root) {
$this->DIRECTORY_ROOT = $root;
}
function prequire($path, $relative = NULL) {
if (empty($relative)):
require $this->DIRECTORY_ROOT.$path;
else:
require $path;
endif;
}
function prequire_once($path, $relative = NULL) {
if (empty($relative)):
require_once $this->DIRECTORY_ROOT.$path;
else:
require_once $path;
endif;
}
function test() {
echo '<pre>';
print_r(get_required_files());
echo '</pre>';
}
}
?>
Metodou test() si potom můžeme ověřit, jaké soubory byly načteny a odladit chyby.
<?php
// setup.php
$code_mng_str = '/Program Files/Apache Group/Apache/htprivate/general/';
$mycode_mng_str = '/Program Files/Apache Group/Apache/htprivate/project/';
require_once ($code_mng_str.'code/class.codemanagement.php');
$code_manager = new code_manager($code_mng_str);
$mycode_manager = new code_manager($mycode_mng_str);
$mycode_manager->prequire_once('code/general.php');
load_template();
?>
Právě na tomto jediném místě se určí cesty do adresářů, kde udržujeme kód PHP programů, knihovny funkcí, deklarace tříd. Objekty CODE MANAGERA lze inicializovat i relativně položenou cestou. Musíme přitom pamatovat, že vždy relativně k veřejně uloženému programu. V souboru, který jsem pojmenoval setup.php rovnou includuji soubor general.php a nástroj pro práci se šablonami. Pokud vím, že tento nástroj používám ve všech programech, nebudu se bát načíst kód již zde:
<?php
// general.php
function load_a() {
global $mycode_manager;
load_c();
$mycode_manager->prequire_once('code/class_a.php');
}
function load_b() {
global $code_manager;
$code_manager->prequire_once('code/class_b.php');
}
function load_c() {
global $code_manager;
$code_manager->prequire_once('code/class_c.php');
}
function load_template() {
global $code_manager;
$code_manager->prequire_once('code/class.template.php');
}
?>
Nyní si to zopakujme. V index.php nejprve načítám setup.php. Zde je uložena absolutní cesta k adresáři general ($code_manager) a project ($mycode_manager). Pro oba adresáře vytvářím instanci objektu CODE MANAGERA. Do adresáře general ukládám všeobecně často užívané deklarace tříd, do adresáře project ukládám takové deklarace, které souvisí jen s daným projektem (může to být například chat, weblog, ankety atd.).
Práci a orientaci dále ulehčí funkce jako load_a(), load_b(), load_c() či load_template(). V případech, kdy jeden objekt využívá druhý a tento je dále závislý na nějakém dalším, se tímto dosáhne elegantního kódu.
Vložení kódu je možné několika způsoby (include, include_once, require, require_once) - v tomto případě se volil require_once(). Analogicky si můžeme definovat metody pinclude() i pinclude_once().
Jelikož se vložení (require_once) kódu provádí v objektu code_manager (přesněji metodou prequire_once), plyne z toho jedno omezení. Nemůžeme totiž například v souboru class_a pracovat s globální proměnnou (objektem, polem apod.) při absenci odkazu na $GLOBALS[]. Z mého pohledu z toho plyne cesta k důslednějšímu OOP. Podívejte se například na soubor db_connect.php (tento kód při načtení CODE MANAGEREM absolutně ztratí smysl):
<?php
$server_name = "localhost";
$db_user = "root";
$db_pass = "sa";
$db_name = "jmeno_databaze";
?>
A nyní tentýž soubor db_connect.php (nyní při použití CODE MANAGERA.. poté pracujeme s objektem $db_connect_info):
<?php
class db_connect_info {
var $server_name = "localhost";
var $db_user = "";
var $db_pass = "";
var $db_name = "sipky_vyvoj";
}
global $db_connect_info;
$db_connect_info = new db_connect_info();
?>
Tak to je řízení vkládání kódu v PHP podle mého. Zdá se vám tato technika naprosto zbytečná či složitá? Nebo používáte zaběhnutou techniku z příruček pro začátečníky, případně máte svou vlastní? Podělte se o své zkušenosti v diskusi.
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Další aktuální články na interval.cz
- Malware: android pod palbou, mobily v ohrožení?
- Pozvánka na Microsoft TechDays 2012
- Reklamní slepota: co to je a jak s ní bojovat?
- Pět důvodů, proč vybrat redakční systém Drupal
- Čeština pro WordPress 3.3.1 k dispozici
Tematicky související články
- DHTML editor - vkládání obrázků
- Weblog v PHP - vkládání, mazání a úprava článků
- PHP a MS SQL - vkládání a načítání souborů
- OOP v PHP: Autoloading
- OOP v PHP: Standard PHP Library (SPL) - základní rozhraní
Dejte vědět i ostatním o článku
Diskuse (počet komentářů: 0)
Buďte prvním návštěvníkem, který přidá nový komentář.

