[OOP] Auf Eigenschaften der Vaterklasse zugreifen?
Sascha
- php
Guten Tag,
ich habe ein kleines Problem mit der OOP in PHP5. Ich möchte aus einer Childklasse auf eine Eigenschaft (Variable) der Vaterklasse zugreifen.
Im Code sieht das wie folgt aus:
class listbox
{
public $items;
public $items_collection;
private $browser;
function __construct()
{
$this->items = new list_item_f;
}
public function items($index)
{
return $this->items_colletion[$index];
}
...
//Hier werden die Funktionen für listbox->items festgelegt.
class list_item_f extends listbox
{
function __construct()
{
//echo "test";
//echo get_parent_class($this);
}
public function add($value)
{
$this->items_collection[] = new list_item;
$index = count($this->items_collection) - 1;
$this->items_collection[$index]->value = $value;
...
Im Hauptprogramm erfolgt der Zugriff über folgenden Aufruf:
include('listbox.php');
$list = new listbox;
$list->items->add("1.Item");
echo $list->items(0)->value;
Leider bekomme ich keine Ausgabe. Ich vermute, dass der Fehler in dieser Zeile liegt: >$this->items_collection[] = new list_item;<. Das System greift hier wohl nicht auf die Eigenschaft der Vaterklasse zurück, sondern legt eine eigene items-collection Eigenschaft an.
Mit parent::methode kann ich auf Methoden der Vaterklasse zurückgreifen. Gibt es sowas auch für Eigenschaften (Variablen)?
PS: Ich hoffe, dass ich mein Problem einigermaßen verständlich darstellen konnte.
PS2: Zum Sinn des Ganzen: Ich möchte einige Steuerelemente, die zB: in Visual Basic eingesetzt werden, mit PHP nachbauen. Vom Syntax her soll es sich an .NET orientieren.
Hi,
class listbox
{
public $items;
public $items_collection;
private $browser;function __construct()
{
$this->items = new list_item_f;
}public function items($index) {
Sowohl eine Eigenschaft als auch eine Methode mit dem Bezeichner 'items' zu benennen, ist vielleicht nicht so clever.
MfG ChrisB
--
Light travels faster than sound - that's why most people appear bright until you hear them speak.
Hi,
Sowohl eine Eigenschaft als auch eine Methode mit dem Bezeichner 'items' zu benennen, ist vielleicht nicht so clever.
MfG ChrisB
Hi,
also technisch scheint dies keine Probleme zu bereiten. Denn, wenn ich innerhalb der Methode 'items' ein "echo 'test'" notiere und diese Methode dann aufrufe wird test ausgegeben. Wenn ich innerhalb der Vaterklasse die Eigenschaft 'items' manipuliere funktioniert das auch. Nur in einer Childklasse bekomme ich keinen Zugriff auf die Eigenschaft 'items'. Ich bin der Meinung, dass ich die Eigenschaft falsch aufrufe. Aber ich lasse mich gerne eines besseren belehren :)
Sinn des Ganzen ist, wie oben erwähnt, solche Konstrukte zu ermöglichen:
$list->items->add("1.Item");
echo $list->items(0)->value;
$list->items->remove(0);
//ect..
Was zB. in Visual Basic.NET Gang und Gebe ist.
Hi,
Wenn ich innerhalb der Vaterklasse die Eigenschaft 'items' manipuliere funktioniert das auch. Nur in einer Childklasse bekomme ich keinen Zugriff auf die Eigenschaft 'items'.
Natürlich bekommst du - auf dessen eigene "Version" von items.
Aber von einer *Instanz* der Vaterklasse weiss deine Childklasse doch gar nichts.
Mit dem Scope Resolution Operator (::) kommst du natürlich an die Vaterklasse - aber kannst nur auf deren statische Eigenschaften zugreifen.
Sinn des Ganzen ist, wie oben erwähnt, solche Konstrukte zu ermöglichen:
$list->items->add("1.Item");
echo $list->items(0)->value;
$list->items->remove(0);
//ect..
Und der Sinn des Konstruktes an sich soll sein ...?
> Was zB. in Visual Basic.NET Gang und Gebe ist.
PHP ist aber nicht SpracheXY.
MfG ChrisB
--
Light travels faster than sound - that's why most people appear bright until you hear them speak.
Hi,
Sinn des Ganzen ist, wie oben erwähnt, solche Konstrukte zu ermöglichen:
$list->items->add("1.Item");
echo $list->items(0)->value;
$list->items->remove(0);
//ect..
>
> Und der Sinn des Konstruktes an sich soll sein ...?
>
> > Was zB. in Visual Basic.NET Gang und Gebe ist.
>
> PHP ist aber nicht SpracheXY.
>
> MfG ChrisB
>
>
Der Sinn ist, dass ich in PHP einige Steuerlemente, die in der Entwicklung für Desktopanwendungen genutzt werden, nachbauen und als vorgefertigte Klassen zur Verfügung stellen möchte. DataGrid, ListView, TreeView seien mal als Beispiel genannt.
Dies soll die Entwicklung von Rich Internet Applications unterstützen. Der Syntax soll dabei an den von .NET angelehnt sein.
Moin!
ich habe ein kleines Problem mit der OOP in PHP5. Ich möchte aus einer Childklasse auf eine Eigenschaft (Variable) der Vaterklasse zugreifen.
Lässt du dir mit error_reporting(E_ALL) auch Notices bei Zugriffen auf nichtexistente Variablen ausgeben?
Ich vermute mal: Nein.
Andernfalls wäre dir der Tippfehler aufgefallen:
public $items_collection;
return $this->items_colletion[$index];
Da fehlt mal ein "c".
Leider bekomme ich keine Ausgabe. Ich vermute, dass der Fehler in dieser Zeile liegt: >$this->items_collection[] = new list_item;<. Das System greift hier wohl nicht auf die Eigenschaft der Vaterklasse zurück, sondern legt eine eigene items-collection Eigenschaft an.
Wenn dein Code tatsächlich stimmt, dann liegst du falsch. Die Eigenschaft items_collection wird erweitert, aber wenn du dir die nicht existente Eigenschaft items_colletion (ohne "c") zurückgeben lässt, bringt dir das nicht viel.
- Sven Rautenberg
Hi!
ich habe ein kleines Problem mit der OOP in PHP5.
Auch bei OOP in PHP5 sind die grundlegenden Debuggingmittel, error_reporting auf E_ALL stellen und Kontrollausgaben, von Vorteil, um Fehler zu finden. (Den von Sven erwähnten Tippfehler hab ich korrigiert.)
Ich möchte aus einer Childklasse auf eine Eigenschaft (Variable) der Vaterklasse zugreifen.
Das ist kein Problem, nur das worauf du zugreifen willst, existiert schlicht nicht.
$list = new listbox;
var_dump($list);
object(listbox)#1 (3) {
["items"]=>
object(list_item_f)#2 (3) {
["items"]=>
NULL
["items_collection"]=>
NULL
["browser:private"]=>
NULL
}
["items_collection"]=>
NULL
["browser:private"]=>
NULL
}
$list->items existiert. Soweit so gut.
$list->items->add("1.Item");
var_dump($list);
object(listbox)#1 (3) {
["items"]=>
object(list_item_f)#2 (3) {
["items"]=>
NULL
["items_collection"]=>
array(1) {
[0]=>
object(list_item)#3 (1) {
["value"]=>
string(6) "1.Item"
}
}
["browser:private"]=>
NULL
}
["items_collection"]=>
NULL
["browser:private"]=>
NULL
}
Jetzt gibt es $list->items->items_collection[0]
echo $list->items(0)->value;
Und was macht deine Methode $list->items(0)?
public function items($index)
{
return $this->items_collection[$index];
}
Sie greift auf $list->items_collection zu, was aber NULL ist, weil du es bisher nicht initialisiert hast. Das hat eine Notice zur Folge
Notice: Trying to get property of non-object in ... on line ...
die du nur mit dem E_ALL-error_reporting siehst. Die Kontrollausgabe
var_dump($list->items(0));
liefert ebenfalls NULL. Kein Objekt -> keine Propertys.
Abgesehen davon ist die Methode listbox::items() derzeit relativ zweckfrei. Wenn sie wenigstens eine Index-Prüfung enthielte ...
Und außerdem müsste man noch stutzig werden, warum es nicht bereits in der Methode listbox::items() zu einer Fehlermeldung kam, denn $this->items_collection ist ja NULL und $this->items_collection[$index] greift theoretisch auf einen Index von NULL zu. Warum da keine Meldung kommt, kann ich nicht beantworten. Es hätte aber Notice-Meldungen gegeben, wenn du nicht einfach nur Eigenschaften benennst, sondern ihnen auch einen Default-Wert zuwiesest.
public $items_collection = array();
Und damit gibt es dann auch eine Meldung
Notice: Undefined offset: 0 in ... on line ...
die einen zur Kontrolle der items_collection veranlassen könnte.
Ich vermute, ...
Lass dir deine Vermutungen immer mit Kontrollausgaben bestätigen oder widerlegen!
PS2: Zum Sinn des Ganzen: Ich möchte einige Steuerelemente, die zB: in Visual Basic eingesetzt werden, mit PHP nachbauen. Vom Syntax her soll es sich an .NET orientieren.
Da ging es mir vor einiger Zeit vermutlich ebenso wie dir. Die Idee, .NET-Elemente mit PHP nachzubauen, habe ich aber wieder verworfen. Die Möglichkeiten und vor allem auch Notwendigkeiten unter .NET sind ganz andere als unter PHP. Das teilweise 1:1 nachzubauen bringt wenig außer erhöhter Codekomplexität und Laufzeit. Ein Array unter .NET ist etwas starres. Einmal definiert, ist seine Größe nicht mehr änderbar. Deshalb gibt es da zusätzlich noch Konstrukte wie Collections, die einfach übergebene Objekte hinzunehmen, ohne dass man vorher wissen muss, vieviele es einmal werden. Außerdem gibt es für die verschiedenen Anwendungsfälle verschiedenen Typen von Sammlungen (Collection, Hashtable, Dictionary, und so weiter). PHP hat mit seinem Array-Typ ein universelles Sammlungs"objekt" im Angebot. Es kann verwendet werden als array, list (vector), hash table (an implementation of a map), dictionary, collection, stack, queue, and probably more. Die Notwendigkeit von speziellen Zugriffsfunktionen oder Indexern wie unter .NET ist einfach nicht gegeben, denn die Zugriffsmöglichkeiten, die es bereits von Haus aus mitbringt reichen für den normalen Gebrauch.
KISS. Keep It Short and Simple. Nutze die vorhandenen Möglichkeiten anstatt Kapselungen einzubauen, die nur Laufzeit verbrauchen. Und schau dir die SPL an (ein weiterführender Link ist im Kapitel Introduction zu finden), da findest du jede Menge interessante Klassen und Interfaces, wie ArrayAccess, Countable, Iteratoren, mit denen du zusätzliche Funktionalitäten hinzufügen kannst, das Ergebnis sich aber weiterhin wie PHP anfühlt.
Zum Üben und Erfahrung sammeln (auch negativer) kannst du ja an deinem Vorhaben (noch ein Weilchen) festhalten, aber vom Ziel, es in der derzeit angedachten Form irgendwann produktiv einzusetzen (wenn du das vorhast), rate ich ab.
Lo!
@Sven und dedflix
Danke für den Tip bezüglich error_reporting(E_ALL). Das war mir ganz entfallen.
Den Schreibfehler hatte ich gestern abend noch gefunden.
Mit aktiviertem error_reporting kommen die zitierten Fehlermeldungen zustanden.
Wenn ich folgendes ausführe:
$list->items->add("1.Item");
$list->items->add("2.Item");
$list->items->add("3.Item");
Dann kann ich item_collection nur, wie folgt, abfragen:
foreach($list->items->items_collection as $item)
{
echo $item->value."<br>";
}
Aber ich ging davon aus, dass bei diesem Konstrukt:
class list_item_f extends listbox
{
function __construct()
{
}
public function add($value)
{
parent::addItemInternal($value);
}
jeder Wert, der über listbox::items->add($VALUE) an listbox::addItemInternal($VALUE) weitergereicht wird und dadurch nur auf die items_collection der Vaterklasse(listbox) zugegriffen wird und somit eigentlich folgendes möglich sei:
foreach($list->items_collection as $item)
{
echo $item->value."<br>";
}
PS: Es gibt in der Klasse 'listbox' eine Methode 'items', die einen einzelnen Eintrag aus dem Array items_collection zurückgibt und eine Eigenschaft 'items', die die ganzen Methoden für die Manipulation des gesamten 'item_collection' Arrays enthält, zB: add / remove etc.
In .NET würde es, wie folgt, aussehen:
ListBox1.Items.Add("1.Eintrag")
MsgBox(ListBox1.Items(0).ToString)
Eine Änderung der Methode 'items' in 'item', um Konflikte zwischen Methode und Eigenschaft auzuschließen, brachte auch keine Besserung.
-----------------------------------------------------------------
Zur .NET Geschichte:
Ziel soll nicht sein .NET nachzubauen ;) Ich will vielmehr nur einige Steuerelemente, zB. ListView, als PHP Klasse umsetzen. Die optische Darstellung soll, wenn der Nutzer es nicht anders will, auch vom Skript übernommen werden. In Sachen .NET war nur geplant, dass die Bedienung dieser Klasse(n) an den .NET Syntax angelehnt sein soll. Mit allem soll die Entwicklung von RIAs erleichtert werden.
Altes Beispiel für eine ListView Klasse:
http://aldbt.al.funpic.de/elements/
Hier noch ein paar ältere Versuche:
http://aldbt.al.funpic.de/te/npc.php
http://aldbt.al.funpic.de/te/te/window.php
Hi!
Dein Problem ist nicht die Vererbung der Klassen sondern die Anordnung deiner Instanzen. Das ist deine jetzige Struktur:
$listbox = new listbox();
$listbox->items ->(new list_item_f)->items
->items_collection
->items_collection
Das sind zwei Objekte und vier unabhängige Eigenschaften.
$listbox = new list_item_f();
ergäbe stattdessen
$listbox->items
->items_collection
mit einem ungenutzten items und der items_collection, die sowohl über die geerbte Methode items() als auch über add() von list_item_f angesprochen werden kann.
Du musst erstmal die Zuständigkeiten in deinem Konzept sortieren. Wenn $items eine Instanz einer ItemsCollection sein soll, dann ist es Aufgabe der ItemsCollection, sich um die Items zu kümmern. Die Listbox selbst hält dann nur einen Verweis auf die Instanz der ItemsCollection aber selbst keinerlei Infrastruktur für die einzelnen Items vor. Wenn die Listbox ein Item braucht, dann fragt sie die ItemsCollection nach eben diesem. Sie greift da nicht einfach selbst durch.
Aber ich ging davon aus, dass [...]
Ja, das habe ich schon aus deinem Ursprungsposting gelesen. Aber wie ist es jetzt? Hast du nun verstanden, wo dein Fehler war?
Eine Änderung der Methode 'items' in 'item', um Konflikte zwischen Methode und Eigenschaft auzuschließen, brachte auch keine Besserung.
Ja klar, mir zumindest, dir jetzt auch?
PS: Es gibt in der Klasse 'listbox' eine Methode 'items', die einen einzelnen Eintrag aus dem Array items_collection zurückgibt und eine Eigenschaft 'items', die die ganzen Methoden für die Manipulation des gesamten 'item_collection' Arrays enthält, zB: add / remove etc.
In .NET würde es, wie folgt, aussehen:
ListBox1.Items.Add("1.Eintrag")
MsgBox(ListBox1.Items(0).ToString)
Nein, nicht .NET sondern Visual Basic. In C# schriebe man
MessageBox(ListBox1.Items[0].ToString())
also eckige Klammern nach Items. Damit sieht man gleich, dass Items keine Funktion ist, sondern dass hier ein Index-Zugriff stattfindet (gelöst über eine Spezialität namens Indexer). Dieses Verhalten kannst du unter PHP nachbilden, wenn du dir die bereits empfohlene SPL ansiehst und dort speziell das Interface ArrayAccess. Wenn du das in der ItemsCollection-Klasse implementiert hast und $listbox->items auf eine Instanz davon verweist, kannst du darauf weiterhin als Objekt zugreifen ($listbox->items->add()) aber auch wie auf ein Array ($listbox->items[0]). Andere Funktionalitäten verlangen die Implementation weiterer Interfaces. Für count($listbox->items) braucht es Countable und foreach ($listbox->items as $item) benötigt das Interface Iterator oder noch besser IteratorAggregate. Mit Iterator kannst du nur eine Iteration verwalten, IteratorAggregate ergibt hingegen voneinander unabhängige Iteratoren.
> Zur .NET Geschichte:
> Ziel soll nicht sein .NET nachzubauen ;) Ich will vielmehr nur einige Steuerelemente, zB. ListView, als PHP Klasse umsetzen.
Ja, ich hab dein Ziel schon verstanden, ich hatte ja ein solches ja früher selbst einmal für einen kurzen Augenblick. Orientiere dich aber besser nicht nach den Notwendigkeiten von .NET sondern an den Möglichkeiten von PHP nebst dessen Philosophie. .NET-Komponenten sind ziemlich umfangreich, was Code und Methodenanzahl anbelangt, aber im Gegensatz zu PHP wird es kompiliert und ist dann einigermaßen schnell. Unter PHP muss der Code im Wesentlichen so wie du ihn schreibst ausgeführt werden und nicht wie ein Compiler ihn optimiert hat.
> In Sachen .NET war nur geplant, dass die Bedienung dieser Klasse(n) an den .NET Syntax angelehnt sein soll. Mit allem soll die Entwicklung von RIAs erleichtert werden.
Es sollte meines Erachtens nicht das Ziel sein, die "Umdenkfaulheit" des Entwicklers zu unterstützen, dafür aber jede Menge zu wartenden und vielleicht langsam laufenden Code in Kauf zu nehmen.
Lo!
Hi,
Durch etwas herumprobieren bin ich der Fehlerursache schon etwas näher gekommen.
Ich werde mein Konzept nun überdenken.
Gruß Sascha