Verfügbarkeiten von Variablen innerhalb eines Scripts

Artikel, Anleitungen, Minikurse und Leitfaden für alle möglichen PC-Themen und php/phpBB.
Antworten
Benutzeravatar
oxpus
Administrator
Administrator
Beiträge: 29111
Registriert: Mo 27.Jan, 2003 22:13
Wohnort: Bad Wildungen
Kontaktdaten:

Verfügbarkeiten von Variablen innerhalb eines Scripts

Beitrag von oxpus » Fr 02.Dez, 2005 11:48

PHP benutzt, wie die meisten modernen Programmiersprachen auch, ein objektorientiertes Modell zur Bearbeitung und Verwaltung von Werten innerhalb Variablen, Konstanten und Arrays.

Das hört sich nun extrem kompliziert an und keiner kann erstmal damit etwas anfangen, aber wir werden das Rätzel nun Stück für Stück auflösen.

Fangen wir mit dem Modell der Scripte anhand des phpBB an, auf das wir uns in diesem Exkurs auch beschränken werden.

Jedes Script in einem PHP wird zunächst von PHP als einzelnes "Programm" behandelt (Ich wähle hier bewusst diese Wortwahl, damit sich das jeder besser vorstellen kann).
Innerhalb eines Script läuft die Bearbeitung sämtlicher Bedingungen, Variablen, Wertzuweisungen, Schleifen, etc. völlig autark und damit unabhängig aller anderen Scripte ab, die ebenfalls zur Verfügung stehen.
Aber damit kann man kein komplexes System erstellen, da dieses ja auch mehr als nur eine Datei verlangt, allein schon wegen der Übersichtlichkeit.
Und Aktionen der Anwender führen ja auch zu Aufrufen eines, des oder anderer Scripte.

Wie kann das also gelöst werden?
PHP bietet hierzu zunächst die Möglichkeit, andere Scripte in einem Script einzubinden und damit ebenfalls verfügbar zu machen.
Das geschieht mit den 4 möglichen Befehlen

require();
require_once();
include();
include_once();

require(); und include(); unterscheiden sich hier in der Fehlerroutine. So wird ein mit require eingebundenes Script als benötigt deklariert, so daß die weitere Bearbeitung anhält, wenn PHP die angegebene Datei nicht finden kann.
Scripte, die mittels include(); eingebunden werden, führen bei einem "Nichtfinden" zu keinem Fehler, führen aber spätestens bei der Benutzung der damit bereitgestellten Bearbeitungsschritte zu einer Fehlermeldung.

Die jeweiligen Zusätze "_once" binden ein Script nur einmalig ein. PHP prüft damit nach, ob die Datei bereits eingebunden ist und wiederholt diesen Vorgang nicht noch einmal.

Es kann durchaus Sinn machen, ein Script mehrmals einzubinden, also "_once" nicht zu verwenden, da mit einem require(); oder include(); die eingebundene Datei genau in dem Moment abgearbeitet wird. Somit könnten z. B. Werte, die aktuell aus einer Datei oder einer Tabelle gelesen werden müssen, auch wirklich immer aktuell zur Verfügung gestellt werden.
Enthalten die eingebundenen Scripte hingegen Klassen- oder Funktiondefinitionen, wird eine PHP-Fehlermeldung angezeigt, da man genau diese jeweils nur einmal zum Scriptaufruf definieren werden dürfen. Macht ja auch sonst nur wenig Sinn, eine Funktion mehrfach zu definieren. Einmal reicht schliesslich.

PHP kann aber auch weitere Scripte verwenden, in dem per HTML-Link das Script aufgerufen wird und mittels Parameterübergabe das neue Script diese Werte verwenden kann, um Aktionen auszulösen oder Berechnungen / Anzeigen / Ausgaben durchzuführen.

Soweit die Grundlagen.
Aber was hat das nun mit der lang_main.php zu tun?
Da kommen wir jetzt genau hin!

Jedes Script in phpBB, daß man direkt per Link aufrufen kann, also z. B. die viewforum.php, bindet mindestens 2 Dateien per include(); ein.
Das ist zum einen die extension.inc, in der die Dateiendung der PHP-Scripte definiert wird (DER zentrale Anlaufpunkt, wenn man mal diese eben ändern möchte - solange sich alle Scripte an die phpBB-Vorgaben halten!) und die common.php, in der alle wichtigen, zum phpBB-Kern gehörenden Dateien mit eingebunden werden.

Eine der Dateien ist die functions.php, in der die Benutzerdaten vorbereitet werden, wie z. B. auch die Sprache, der verwendete Style, die Userdaten selber, etc.
Die ebenfalls eingebundene sessions.php ist eine zentral wichtige Datei, da hier die Userdaten aus der Datenbank gelesen und bereitgestellt werden. Dieses geschieht durch einen Aufruf aus der functions.php heraus.
Daneben gibts es auch noch weitere, für phpBB immer wichtige Dateien, die wie hier aber mal ausklammern.

Nun haben wir schon ansatzweise erfahren, wie die Sprache eingebunden wird, aber wie geschieht das genau?
phpBB macht das in 2 Phasen:

Phase 1 includiert alle wichtigen Dateien, für die lang_main.php wären das zunächst die oben erwähnte functions.php für die Aufbereitung der Userdaten und die sessions.php, die eine Session für den User erstellt, ihn damit eindeutig identifiziert und die Userdaten eben aus der Datenbank ausliest.
Diese Aktion wird in phpBB ausgeführt mittels diesem Code-Block, der in jeder direkt ausführbaren PHGP-Datei zu finden ist (teilweise nur marginal angepasst):

Code: Alles auswählen

define('IN_PHPBB', true); 
$phpbb_root_path = './'; 
include($phpbb_root_path . 'extension.inc'); 
include($phpbb_root_path . 'common.'.$phpEx); 
Neben der Konstanten "IN_PHPBB", die einen "Schutzring" um das Script zieht und der Pfad-Variablen $phpbb_root_path wird die PHP-Dateiendung und eben bereits o. g. common.php eingebunden.

In Phase 2 werden nun die Aktionen angestossen, um eben alles, was nun eingebunden, deklariert und damit vorbereitet wurde auch zu verwenden.
Dieses geschieht in phpBB mittels eines zentralen Session Managements und sieht in jedem (wiederum) direkt ausführbaren phpBB-Script so aus:

Code: Alles auswählen

$userdata = session_pagestart($user_ip, PAGE_GROUPCP);
init_userprefs($userdata);
Dieses ist ein Beispiel aus der groupcp.php, der Benutzergruppenverwaltung.
Die einzigste Unterscheidung dieser Datei im phpBB-Konstrukt zu anderen Dateien ist der Wert nach $user_ip im Funktionsaufruf session_pagestart();.
Genau dieser Wert definiert in der Session die Seite, auf der sich der User gerade befindet und zeigt dieses z. B. auch in der "Wer ist Online"-Liste an.
Diese Funktion erstellt nun eine Sitzung, bzw. ordnet eine bestehende Sitzung diesem User zu.
Mit der zweiten Funktion init_userprefs(); werden nun die userabhängigen Boardbereiche eingestellt, die bereits aus der Datenbank ausgelesen und durch die Funktion session_pagestart(); in das Array $userdata geladen wurden.
In der Funktion init_userprefs();, die in der Datei includes/functions.php zu finden ist, werden also unter anderem die Sprachfiles eingebunden, wie eben auch unsere lang_main.php.
Damit steht also in dem Script der Inhalt diese Datei komplett zur Verfügung.

FALSCH! Genau das tut die Funktion eben so noch NICHT!

Zumindest solange in der Funktion keine Variablen, bzw. Arrays globalisiert oder zurückgegeben werden. Denn dann wären genau diese Werte auch nicht verfügbar!
Und wie genau geht das, bzw. was ist das überhaupt?

Hier müssen wir erst einmal berücksichtigen, daß PHP alle innerhalb eines Scriptes verwendeten Variablen und Arrays nur eben innerhalb dieses Scripts kennt und verwendet. Andere Scripte können auf diese Werte damit zunächst nicht zugreifen.
Schön, aber wie erhalten ich dann die Werte aus der lang_main.php zurück? Es wurde doch eben gesagt, das aus der Funktion zunächst nichts zurück kommt?

Dafür gibt es 3 Wege:
- Variablen/Arrays werden in der Definition der Funktion als Referenz eingebunden (mittels vorangestelltem "&")
- Eine Variable oder ein Array wird mit $return; zurückgegeben
- Eine Variable oder ein Array werden mit global; globalisiert.

Die erste Variante wird meist verwendet, wenn z. B. Arrays, also gruppierte Variablen (vereinfacht gesagt) neue Werte erhalten sollen oder können. Hier ist die 2. Methode, etwas per return; aus der Funktion an das Script zurückzugeben, nicht immer die geschicktere Lösung. Kommt aber auch darauf an, wie man das Script aufbaut:
Die Userdaten werden wie oben beschrieben durch $userdata = session_pagestart($user_ip, PAGE_GROUPCP); durch die Funktion abgefragt und von dort mittels return $userdata; eben zurückgegeben, das Array $post_data wird in der Funktion prepare_post() u. U. verändert, aber nicht direkt zurückgegeben, da diese ja nicht ergänzt werden.
Dabei könnte aber auch das Array $userdata innerhalb der Funktion auch anders genannt sein!

Wie, warum denn das nun wieder?

Das ist schnell erklärt:
Wie ein Script, so werden auch Funktionen autark behandelt, also alle Werte innerhalb einer Funktion sind auch nur dort bekannt!
So kann man z. B. $userdata im Script verwenden, eine Funktion kennt aber nur $user_array!
Auch ist bereits in der Definition einer Funktion jeder Variablen/Array-Name bereits unabhängig des aufrufenden Scripts. Im Funktionsaufruf im Script müssen hingegen die Variablen des Scripts verwendet werden!

Und damit wären wir bei der 3. Variante, der Globalisierung.
Diese Möglichkeit wird auch in der Funktion init_userprefs() verwendet, um eben z. B. alle Werte der lang_main.php dem Script zur Verfügung zu stellen.
Im Detail schaut das beispielsweise so aus:

Code: Alles auswählen

function init_userprefs($userdata)
{
	global $board_config, $theme, $images;
	global $template, $lang, $phpEx, $phpbb_root_path;
	global $nav_links;
Damit stehen der Funktion alle Werte des Arrays $userdata zur Verfügung (die hier wie bereits erwähnt anders benannt sein könnte!) sowie weitere Werte, wie die Board-Einstellungen in $board_config, die Themes in $theme, alle definierten Bilder in $images, ... und die Sprache in $lang.

Aber warum muss das so gemacht werden? Die $lang wird doch erst in dieser Funktion erstellt?
Richtig, die $lang erhält erst durch diese Funktion ihre Inhalte (zumindest in der Regel), die Funktion bereitet aber nur das Board anhand der Userdaten auf und damit wird auch nichts wieder zurückgegeben!

Verrückt?
Nicht wirklich.
Die init_userprefs(); stellt nur sicher, daß Sprache, Style und andere userabhängige Boardeinstellungen eben auch anhand der Userdaten eingestellt werden. So kann das phpBB eben userabhängig individuell eingestellt werden (mehr oder weniger, je nach installierten MODs), bzw. bietet dadurch erst diese Möglichkeiten.

Da nun hierzu eine Vielzahl an Werten bereitzustellen sind, werden diese per global; eben globalisiert, also der gesamten "Welt" und nicht nur der Funktion zur Verfügung gestellt.

Und damit erhält auch die $lang; erst den Status, den man innerhalb eines Scriptes benötigt:
Die Sprachfiles (lang_...php) werden, je nach Notwendigkeit, in der vom User gewählten Sprache eingebunden und schliesslich global bereitgestellt, um diese Texte dann auch zu verwenden und anzeigen zu lassen.

global; wurde dabei aber vordergründig nicht erstellt, um Werte überall bereit zu stellen. Das kann man auch mit PHP-Einstellungen selber erreichen.
global; bietet aber die Möglichkeit, Variablen nicht immer krypischer schreiben zu müssen, um diese in den einzelnen Bereichen zu unterscheiden und eben abgeschlossene Bearbeitungen innerhalb eben der einzelnen Bereiche erst zu ermöglichen, weil eben nicht mit global; bereitgestellte Werte nur in diesem Bereich gültig und damit auch nur dort verfügbar sind.

Fazit:
Will man in phpBB global erstellte Werte, die durch phpBB selber bereits eingebunden werden, auch in eigenen Scripten verwenden, so ist neben der Einbindung der common.php auch das Session-Management zu verwenden, wenn man userabhängige Werte verwenden möchte.
Oder man programmiert sich das selber ;)
Karsten Ude
-={ Das Mädchen für alles }=-
Kein Support per ICQ, Email oder PN! Unaufgeforderte Nachrichten werden ignoriert!
No support per ICQ, Email or PM. Each unasked message will be ignored!

Antworten