PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PHP - Wie sieht gutes Code-Design aus? Wann "echo"?


hofmetzger
2005-08-14, 22:56:48
(edit: uups, wohin gehört php eigentlich? programmierung oder webdesign?)

Hallo zusammen!

Ich bringe mir gerade PHP bei - dank Semesterferien komme ich schnell voran. In Tutorials im Netz lernt man meist schnell, wie bekannte Programmier-Konzepte in PHP funktionieren. Soviel zum Spass...

Nun schreibe ich in C++ zum Beispiel alles frei heraus auf die Konsole was ich lesen will. So erklärt sich vielleicht, warum Teile meines PHP-Codes so aussehen:

echo "Du kannst festlegen, welchen Registrierungsstatus ein Besucher benötigt, ";
echo "um deine Daten lesen zu duerfen:<br>";
echo "<li>Sichtbar fuer jeden Besucher:<br>Keine Einschraenkungen</li>";
echo "<li>Sichtbar fuer jeden 'abi2000':<br>Schwache Einschränkung: Alle ";
echo "Besucher, die das Standardpasswort kennen, registrierte Abis und ";
echo "Administratoren duerfen deine Daten sehen</li>";
...


Nun hab ich in anderen Skripten gesehen, dass nicht nur html von php unterbrochen werden kann, sondern auch umgekehrt. Ich hätte also den gesamten Abschnitt in "?>" und <?php" stecken können und darin ganz gewöhnliches html schreiben können. Das scheint sogar in Switch-Case oder if-Abfragen zu funktionieren.
Oder als Zwischenlösung ein echo mit einem String über mehrere Zeilen...

Wie sollte ichs machen? Wie ist es performanter? (parser unterbrechen lassen oder laufend echos schieben?).
Dann hab ich bei html zwischen php auch noch so ein mulmiges Gefühl...

Uff langer Post: gibts noch irgendwelche Designhilfen für schönen Code? bei mir artets in spaghetticode aus, schöner Code lässt sich in C++, Java oder Python imho viel leichter schreiben... :(

Marscel
2005-08-14, 23:21:52
So eine Struktur:
<? if(...) { ?> HTML <? } ?>

ist meiner Meinung nach einfach unsinnig, wenn man nicht gerade extrem statisch eine HTML-Seite hinbekommen will, denn Code, der weiter unten steht, kann nichts weiter oben im HTML-Dokument bewirken, z.B. wenn unten eine Fehlermeldung initialisiert wird, sie über dem Dokument auszugeben, es sei denn, du willst nen ganzen Block nochmal ausgeben und einen anderen irgendwie unterdrücken. (Endet schnell in Spaghetti-Code.)

Man sollte, wenn man schon so hybridartig schreibt, es lieber so machen:
<? $variable = "Text"; // und andere relevanter PHP Code ?>
<html>...<? print/echo $variable; ?>...</html>

Meiner Erfahrung nach kommt man damit deutlich besser zurecht.
Was die Performance angeht, das ist eigentlich egal, ob du nun mehr echo()s mit kleinen Happen oder ein ganz großes, das das ganze Dokument beinhaltet, schreibst, merken tut man da nichts. Einfach immer schön <br /> schreiben, wenn du was umbrechen willst, das lässt mehr Möglichkeiten.

hofmetzger
2005-08-14, 23:30:06
Man sollte, wenn man schon so hybridartig schreibt, es lieber so machen:
<? $variable = "Text"; // und andere relevanter PHP Code ?>
<html>...<? print/echo $variable; ?>...</html>


Danke für die flotte Antwort! Ich verzichte dann komplett auf "hybridcode" - ist imho auch übersichtlicher.

Coda
2005-08-14, 23:32:35
Am besten Code und HTML komplett trennen per Templates. Ist aber aufwändig.

clm[k1]
2005-08-14, 23:57:09
Am besten Code und HTML komplett trennen per Templates. Ist aber aufwändig.

Es ist vielleicht beim ersten mal mehr zu schreiben, aber der code lässt sich im nachhinein besser warten.


clm[k1]

hofmetzger
2005-08-15, 00:31:20
']Es ist vielleicht beim ersten mal mehr zu schreiben, aber der code lässt sich im nachhinein besser warten.
clm[k1]
Danke euch beiden für den Hinweis.
Hab mich mal (etwas) schlau gemacht, und was mich am meisten reizt, ist die Möglichkeit wieder Nvu zum HTML-Designen zu nutzen, da der HTMLCode ja wieder komplett PHP-frei ist. PHP-Faq (http://faq-php.de/q/q-stil-content-code.html) schlägt mehrere Template-Systeme vor. Könnt ihr mir einen Tipp geben, welches am einfachsten nutzbar/installierbar ist, oder was ihr (warum) benutzt?

darph
2005-08-15, 00:48:18
Ist aber aufwändig.
Nicht wirklich.

http://www.thewebmasters.net/php/FastTemplate.phtml das nehm ich immer her. Simpel, aber mächtig genug für die allermeisten Einsatzbereiche.

Man trennt das Projekt auf in Templates
<p>{LANG_HELLO_WORLD}</p>
und code
$tpl->assign("{LANG_HELLO_WORLD}", "Bonjour, tout le monde");


Edit: Womit wir bei Webdesign wären. :) *verschieb*

z3ck3
2005-08-15, 01:26:59
Also ich hab mitlerweile auch auf templates umgeschwenkt. Ist viel praktischer. Man verteilt den HTML/JS Scheiß auf verschiedene template dateien und die PHPCodes schreibt man in eine andere Datei. Schön getrennt. Am ende des Scriptes wird dann das ganze gecachte zeugs ausgegeben oder wenn z.B. e3in fehler auftritt einfach gelöscht und neue daten in den cache geladen und ausgegeben. IMO ne ganz praktiosche sache. So lassen sich auch inhalte im nachhinein wieder ändern. z.B. Daten im Header o.ä.

RMC
2005-08-15, 08:29:38
Danke euch beiden für den Hinweis.
Hab mich mal (etwas) schlau gemacht, und was mich am meisten reizt, ist die Möglichkeit wieder Nvu zum HTML-Designen zu nutzen, da der HTMLCode ja wieder komplett PHP-frei ist. PHP-Faq (http://faq-php.de/q/q-stil-content-code.html) schlägt mehrere Template-Systeme vor. Könnt ihr mir einen Tipp geben, welches am einfachsten nutzbar/installierbar ist, oder was ihr (warum) benutzt?


Genau, HTML-Code ist komplett PHP frei und umgekehrt, alles wird voneinander getrennt und kann getrennt bearbeitet werden, ohne im anderen Teil herumzupfuschen. Einfache Erweiterbarkeit und Wartbarkeit!

Ich verwende das IT Template System aus dem PEAR Package. Ist meistens schon bei div. Webserver-Packages mit PHP dabei (zb XAMPP), ansonsten muss man einfach nur ein paar Dateien extra hochladen. Ich find es recht einfach und logisch. Viele Templatesysteme sind nach demselben Prinzip aufgebaut, ich hab mir mal ein anderes angesehen (eins aus der PHP Library ich glaub irgendwas mit PHPLibTemplate kA) aber das war nicht ganz so fein und übersichtlich.

MadMan2k
2005-08-15, 12:30:35
ich bin dann wohl der einzige, der den Code noch in der toString() Methode der Jeweiligen Klasse lässt - es ist mir irgendiwe zu viel Aufwand wegen ein paar Zeilen extra Dateien anzulegen.
Wobei die ganzen preg_replace der Performance bestimmt nicht gut tun.

MadMan2k
2005-08-15, 12:37:11
wobei man eigentlich auch ohne template-engines, nur mit geschickt definierten Incudes auskommen sollte...

Pompos
2005-08-15, 12:54:02
ich bin dann wohl der einzige, der den Code noch in der toString() Methode der Jeweiligen Klasse lässt - es ist mir irgendiwe zu viel Aufwand wegen ein paar Zeilen extra Dateien anzulegen.
Wobei die ganzen preg_replace der Performance bestimmt nicht gut tun.
Bei meiner Template Engine verwende ich, str_replace.... ich denke, dass FastTemplate genau das gleiche macht.

@Threadstarter:
Ich würde bei der Wahl der Engine darauf achten, dass sie nicht so (in meinen Augen) unnützes Zeugs wie die Auswertung von IF und ELSE Anweisungen innerhalb der HTML-Datei unterstützt. Macht meist alles nur noch komplizierter.

z3ck3
2005-08-15, 19:01:26
hmmm das das herzstück meiner kleinen template-engine. Fehlen noch n paar Funktionen, aber des funzt schon einwandfrei:


class hfb_template {
var $templatedir = "";
var $templateext = "";
var $sprache = "";
var $varcache = array();
var $cache = array();

// Variablen cachen die zuletzt noch im Cache gesucht und ersetzt werden
function addvar($variable,$inhalt) {
$this->varcache[$variable] = $inhalt;
return 1;
}

// Cache ausgeben (und "globale Variablen" einfügen)
function toscreen($content) {
$content = stripslashes($content);
echo (strtr($content,$this->varcache));
return 1;
}

// Template laden
function gettpl($template) {
if(!isset($this->cache[$template])) {
$template_file = "{$this->templatedir}{$this->sprache}{$template}{$this->templateext}";
if (file_exists($template_file)) {
$this->cache[$template] = str_replace("\"","\\\"",implode("",file($template_file)));
} else {
return "<b>ERROR: Template not found ($template_file)</b>";
}
}
return $this->cache[$template];
}

}

hofmetzger
2005-08-15, 20:19:58
Ich hab heute versucht von vorne anzufangen, finds aber recht schwierig Templates zu benutzen.
So wie ich bisher codete, gabs nur eine Seite mit Header, der Rest war dynamisch - komplett. Mit Templates könnte ich nun mehrere Seiten erstellen und dynamisch füllen, aber der Vorteil schwindet, wenn ich mehrere dynamische Teile in der Seite habe (schwer zu erklären)...
Da unterscheidet sich auch das HTML-Layout... da ists dann doch einfacher in php...

Aber trotzdem Danke für die Template-Tipps, ich werde sicherlich noch die ein oder andere Seite coden, in der ichs nochmal versuche...

Marscel
2005-08-15, 20:53:42
Dann gibts du meinetwegen den ganzen Bereich zwischen <body> und </body> mit PHP aus, indem meinetwegen der Platzhalter {BODYCONTENT} den durch PHP zu ersetzenden HTML-Code enthält.

Dann wird zwar weniger HTML-Code in der Templatedatei zu finden sein, dafür umso mehr in der PHP-Datei. Die Forumsoftware phpBB2 nutzt ein Template-System, das ich mir nochmal genauer angucken muss, da kannst du das quasi 100% dynamisch, trotz vollem HTML-Template, eine Seite erstellen.

z3ck3
2005-08-15, 23:11:23
Hm mit meinen Templates ists einfacher alles dynamisch zu machen. Man hat sogar den vorteil, das man schnell das Layout ändern kann ohne das man den PHP code antasten muss... hmmm ich weiß net was da schwieriger wird...

ich stückel mir ja die Daten aus mehreren dateien zusammen, je nachdem was ich für die aktuelle seite grad brauche. und wenns nur ne zusätzliche headline ist oder n button oder sonst was.

darph
2005-08-16, 00:35:38
Das FastTemplate hat ein nettes Feature - define_dynamic. Damit kann man Blöcke ausblenden, wiederholen (gut für Tabellen etc) und man kann halt auch dynamisch einzelne Templatedateien inkludieren oder sie auf einen {PLATZHALTER} parsen.

Expandable
2005-08-16, 01:11:22
@Threadstarter:
Ich würde bei der Wahl der Engine darauf achten, dass sie nicht so (in meinen Augen) unnützes Zeugs wie die Auswertung von IF und ELSE Anweisungen innerhalb der HTML-Datei unterstützt. Macht meist alles nur noch komplizierter.

Ich danke Smarty für die Unterstützung von If/elseif/else und foreach/for Anweisungen.

kein if/elseif/else-Support: Das würde zu teilweise extrem umständlichen Code führen.
kein foreach/for-Support: Wie soll man da mehrere Datensätze in einem Template ausgeben? Das würde ohne überhaupt nicht funktionieren! Klar sind die Templates dann nicht mehr schön aufgeräumt. Aber alles, was die Darstellung als HTML-Page betrifft, gehört nun mal in das Template rein und nicht in den PHP-Code. Anbei ein ziemlich extremes Template von mir...


{ * SMARTY * }

{include file="gm_header.tpl" css="um" java="gm_tooltip"}

{section name="loop" loop=$units}

{* Get current statusNum and subStatusNum in a new variable, as Smarty has
problems to access complex arrays with complex variables as keys *}

{assign var=statusNum value=$units[loop]->getSortingField('status')}
{assign var=subStatusNum value=$units[loop]->getSortingField('subStatusNum')}

{* Open main sorting table *}
{if $smarty.section.loop.first === true || $units[loop]->getSortingField($mainSorting) != $units[$smarty.section.loop.index_prev]->getSortingField($mainSorting)}
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="margin-bottom: 10px;">
<tr>
{if $d_settings.noMainDesc != 1}
<td width="135" valign="top" onClick="javascript:parent.openSettingsDialog()">
<div class="unitList_info">
{if $mainSorting == 'status'}
{$status->statusObjects[$statusNum]->statusName|truncate:16:"":true}
{else}
{$units[loop]->getSortingField($mainSorting)|truncate:16:"":true}
{/if}
</div>
</td>
{/if}
<td width="*" valign="top">
{/if}

{* Open subStatus table, if mainSorting is status *}
{if $mainSorting == 'status' && ($smarty.section.loop.first === true || $units[loop]->getSortingField('subStatusNum') != $units[$smarty.section.loop.index_prev]->getSortingField('subStatusNum') || $units[loop]->getSortingField($mainSorting) != $units[$smarty.section.loop.index_prev]->getSortingField($mainSorting))}
{if $status->statusObjects[$statusNum]->allowSubs === true}
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
{if $d_settings.noMainDesc != 1}
<td width="135" valign="top" onClick="javascript:openPopup('index.php?module=um&page=status&action=subStatusInfo&statusNum={$statusNum}&subStatusNum={$subStatusNum}', 'subStatusInfo{$subStatusNum}', 670, 430, 'yes')">
<div class="unitList_info">
({$subStatusNum})
{$status->statusObjects[$statusNum]->subStatusObjects[$subStatusNum]->subName|truncate:11:"":true}
</div>
</td>
{/if}
<td width="*" valign="top">
{/if}
{/if}

{* Open subSorting table (if subSorting is set) *}
{if $subSorting != '' && ($smarty.section.loop.first === true || ($mainSorting == 'status' && $units[loop]->getSortingField('subStatusNum') != $units[$smarty.section.loop.index_prev]->getSortingField('subStatusNum')) || $units[loop]->getSortingField($mainSorting) != $units[$smarty.section.loop.index_prev]->getSortingField($mainSorting) || $units[loop]->getSortingField($subSorting) != $units[$smarty.section.loop.index_prev]->getSortingField($subSorting))}
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
{if $d_settings.noSubDesc != 1}
<td width="135" valign="top" onClick="javascript:parent.openSettingsDialog()">
<div class="unitList_info">
{if $subSorting == 'status'}
{$status->statusObjects[$statusNum]->statusName|truncate:16:"":true}
{else}
{$units[loop]->getSortingField($subSorting)|truncate:16:"":true}
{/if}
</div>
</td>
{/if}
<td width="*" valign="top">
{/if}

{* Open subStatus table, if subSorting is status *}
{if $subSorting == 'status' && ($smarty.section.loop.first === true || $units[loop]->getSortingField('subStatusNum') != $units[$smarty.section.loop.index_prev]->getSortingField('subStatusNum') || $units[loop]->getSortingField($mainSorting) != $units[$smarty.section.loop.index_prev]->getSortingField($mainSorting) || $units[loop]->getSortingField($subSorting) != $units[$smarty.section.loop.index_prev]->getSortingField($subSorting))}
{if $status->statusObjects[$statusNum]->allowSubs === true}
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
{if $d_settings.noSubDesc != 1}
<td width="135" valign="top" onClick="javascript:openPopup('index.php?module=um&page=status&action=subStatusInfo&statusNum={$statusNum}&subStatusNum={$subStatusNum}', 'subStatusInfo{$subStatusNum}', 670, 430, 'yes')">
<div class="unitList_info">
({$subStatusNum})
{$status->statusObjects[$statusNum]->subStatusObjects[$subStatusNum]->subName|truncate:11:"":true}
</div>
</td>
{/if}
<td width="*" valign="top">
{/if}
{/if}

{* Show unit info *}
<table width="131" class="unitList_{$units[loop]->unitType}" bgcolor="#{if $d_settings.noColor != 1}{$status->statusObjects[$statusNum]->statusColor}{else}FFFFFF{/if}" cellpadding="0" cellspacing="0">
<tr>
<td onClick="javascript:parent.openUnitDialog({$units[loop]->ID})">
<div id="ut{$units[loop]->ID}" style="position: relative;"></div>
<div onMouseOver="showTooltip('{$units[loop]->ID}')" onMouseOut="hideTooltip()">
{if $units[loop]->unitType == "group"}
{$units[loop]->getListString($d_settings.noOrganisation)|escape|truncate:32:"":true}
{else}
{$units[loop]->getListString($d_settings.noOrganisation)|escape|truncate:15:"":true}
{/if}
</div>
<div class="tooltip" id="tt{$units[loop]->ID}" style="background: #{if $d_settings.noColor != 1}{$status->statusObjects[$statusNum]->statusColor}{else}FFFFFF{/if}">
<table border="0" id="tbl{$units[loop]->ID}">
<tr>
<td valign="top">
Einheit:
</td>
<td>
<b>{$units[loop]->unit|escape}</b>
</td>
</tr>
<tr>
<td valign="top">
Organisation:
</td>
<td>
<b>{$units[loop]->organisation|escape}</b>
</td>
</tr>
<tr>
<td valign="top">
Funkrufname:
</td>
<td>
<b>{$units[loop]->radioName|escape} {$units[loop]->radioDigits|escape}</b>
</td>
</tr>
</table>
</div>
</td>
</tr>
</table>

{* Close subStatus table if subSorting is status *}
{if $subSorting == 'status' && ($smarty.section.loop.last === true || $units[loop]->getSortingField('subStatusNum') != $units[$smarty.section.loop.index_next]->getSortingField('subStatusNum') || $units[loop]->getSortingField($mainSorting) != $units[$smarty.section.loop.index_next]->getSortingField($mainSorting) || $units[loop]->getSortingField($subSorting) != $units[$smarty.section.loop.index_next]->getSortingField($subSorting))}
{if $status->statusObjects[$statusNum]->allowSubs === true}
</td>
</tr>
</table>
{/if}
{/if}

{* Close subSorting table (if subSorting is set) *}
{if $subSorting != '' && ($smarty.section.loop.last === true || ($mainSorting == 'status' && $units[loop]->getSortingField('subStatusNum') != $units[$smarty.section.loop.index_next]->getSortingField('subStatusNum')) || $units[loop]->getSortingField($mainSorting) != $units[$smarty.section.loop.index_next]->getSortingField($mainSorting) || $units[loop]->getSortingField($subSorting) != $units[$smarty.section.loop.index_next]->getSortingField($subSorting))}
</td>
</tr>
</table>
{/if}

{* Close subStatus table if mainSorting is status *}
{if $mainSorting == 'status' && ($smarty.section.loop.last === true || $units[loop]->getSortingField('subStatusNum') != $units[$smarty.section.loop.index_next]->getSortingField('subStatusNum') || $units[loop]->getSortingField($mainSorting) != $units[$smarty.section.loop.index_next]->getSortingField($mainSorting))}
{if $status->statusObjects[$statusNum]->allowSubs === true}
</td>
</tr>
</table>
{/if}
{/if}

{* Close mainSorting table *}
{if $smarty.section.loop.last === true || $units[loop]->getSortingField($mainSorting) != $units[$smarty.section.loop.index_next]->getSortingField($mainSorting)}
</td>
</tr>
</table>
{/if}


{sectionelse}
<script type="text/javascript">
document.body.style.background = '#E0E0E0';
</script>

<div align="center">
<br>
<div class="info">
{if $filterInUse === true}
In der Datenbank konnten keine Einheiten gefunden werden, die Ihren Filter-Kriterien
entsprechen. Klicken Sie <a href="javascript:parent.openSettingsDialog('filter')">hier</a>, um die Filter-Einstellungen zu ändern.
{else}
In der Datenbank sind für diesen Einsatz noch keine Einheiten gespeichert!
{/if}
</div>
</div>
{/section}

<script type="text/javascript">
window.setTimeout("reload()", {$updateTime});

window.setTimeout("window.scrollTo(0, {$scrollTo|default:"0"})", 0);

{literal}
function reload()
{
var scrollTo;

if (window.name == 'mainiframe')
parent.hideMenuWhileLoading();

if (typeof window.pageYOffset != 'undefined')
scrollTo = window.pageYOffset;
else
{
if ((!window.document.compatMode) || (window.document.compatMode == 'BackCompat'))
scrollTo = window.document.body.scrollTop;
else
scrollTo = window.document.documentElement.scrollTop;
}

window.location.href = 'index.php?module=um&page=main&scrollTo='+scrollTo;
}
{/literal}

{if $filterInUse eq true}
window.setTimeout("document.body.style.backgroundImage='URL(img/bg_filter.gif)'", 0);
{/if}
</script>

{include file="gm_footer.tpl"}

Der Grund, warum teilweise der gleiche HTML-Code nur mit anderen Variablen drinnen steht liegt darin, dass dies viel performanter ist, als die Tabellen in eine extra Datei auszuglieden und dann immer zu inkludieren. Bei wenigen Durchläufen der Schleife macht das nichts aus, da diese aber leicht bis zu 200, 500 oder gar 1000 mal (oder in Extremsituationen noch öfters) durchlaufen werden kann (und das System wird von standardmäßig 30 Benutzern gleichzeitig benutzt, wobei obige Datei alle 60 Sekunden von jedem Benutzer aufgerufen wird im Normalfall), ist der Performancegewinn deutlichst zu spüren.

z3ck3
2005-08-16, 02:07:52
Bei diesen dingen lässt sich allerdings noch darüber streiten ob man das noch HTML schimpfen kann. Ein paar Varianblen machen das HTML Zeugs ja schon fast kaputt, aber das übersteigt dann doch alles :D

Naja, jedem das seine. Doch muss man so je noch ne weitere Sprache lernen :D Das ist auch das was mich an vielen CMSystemen stört: Es wird zwar einerseits leichter aber andererseits bringt es weitere Probleme mit sich. Darum bastel ich ja auch mein eigenes. Klein aber fein *g*

Allerdings hat mich da grad was auf ne Idee gebracht. ich werd ma drüber nachdenken die Templates in eine Datei zu quetschen, um vor jedem durchlauf eine maintemplate zu öffnen oder sowat... hmmm *drüberleg*

clm[k1]
2005-08-16, 08:47:47
Wo wir gerade bei Templates sind: gibt es für php etwas in der Art wie Tapestry (http://jakarta.apache.org/tapestry/)?

Tapestry ist ein Framework für Java, das deswegen so toll ist, weil es eine Templatesprache enthält, die auf tags basiert.
Also keine blöden if, else und hastenicht gehen. Auch keine blöden Platzhalter - nur HTML mit ein paar extra-tags.

bsp:
<span jwcid="@Insert" value="ognl:new java.util.Date()">June 26 2005</span>

mit dem Insert gibt man an, das das was zwischen dem öffnenden und schließenden span-tag steht, durch das ersetzt wird, was per ognl aufgerufen wird.

Mit einem anderen Tag könnte man angeben, das das mehrmals ausgegeben wird.

Die anderen aspekte von Tapestry wird man in php wohl kaum umsetzen können, aber der erläuterte sollte sich doch machen lassen als Templatesystem.

Weis jemand, ob es ein Templatesystem gibt, das in der Art funktioniert?


clm[k1]