PHP OOP static Problem

02/01/2013 15:17 Mikesch01#1
Hi,

hab ein Problem bei PHP im Objektorienterten Bereich.

index.php
PHP Code:
require_once('cms.class.php');

$cms = new cms(); 
cms.class.php
PHP Code:
class cms {

    private 
$time;

    private static 
$page;
    private static 
$user;
    private static 
$db;
    
    public function 
__construct() {
    
        
$this->setDB();
        
$this->setPage();
        
$this->setUser();
        
        
$this->time time();
        
$this->validateForms();
        
    }
    
    
/*
     * Information about Page
     */
    
    
private function setPage() {
        
self::$page = new page();
    }
    
    public static function 
getPage() {
        return 
self::$page;
    }
    
    
/*
     * Information about User
     */
    
    
private function setUser() {
        
self::$user = new user();
    }
    
    public static function 
getUser() {
        return 
self::$user;
    }
    
    
/*
     * Information about Database
     */
    
    
private function setDB() {
        
self::$db = new db();
    }
    
    public static function 
getDB() {
        return 
self::$db;
    }

page.class.php
PHP Code:
class page  {
    
    private 
$templateDir "templates/";
    
    private 
$pageDir "pages/";
    private 
$pageName;

    public function 
__construct() {
        
$this->setPage();
        
$this->setTemplate();
                echo 
cms::getUser()->getUsers();
    }

Das Problem nun dabei ist, dass ich in der page.class.php nicht auf die statische Funktion getUser() zugreifen kann:
Code:
Fatal error: Call to a member function getUsers() on a non-object in C:\xampp\htdocs\lib\page\page.class.php on line 16
Ich erkenne leider den Fehler nicht. Kann mir da jemand vll weiterhelfen? ;)
02/01/2013 15:20 KoKsPfLaNzE#2
Wenn du Static functions aufrufst wird die klasse nicht instanziert, sprich __construct wird nicht durch laufen, somit wird auch kein User gesetzt. Why machst es net ohne static? Rufst das teil doch sowieso mehr mals auf.
02/01/2013 15:27 Mikesch01#3
Ah iam sorry :D hab ne Information vorenthalten.

Natürlich wird cms einmal instanziiert. Wie soll es denn ohne static funktionieren? Hab natürlich mehrere Klassen.
02/01/2013 15:31 Synatex#4
Warum solltest du es mit statischen lösen?

Diese hebeln eigentlich genau den OOP Effekt aus wenn man sie für ein Objekt nutzt was mehrmals gebraucht wird.. Stichwort Singelton und statische Objekte.

Du erstellst dein CMS, übergibst dann entweder das Objekt an die Page-Klasse oder extendest die Page-Klasse mit den Funktionen von dem CMS, damit sie zusammenarbeiten.

Für sowas nutzt man aber keine statischen Methoden.
02/01/2013 15:38 Mikesch01#5
Hm, aber wie löse ich das mit der Datenbank bitte, wenn ich kein statisches Objekt habe? Ich instanziiere das Objekt ja in cms.class.php, aber möchte es in mehreren anderen Klassen verwenden, die in cms.class.php auch defniert sind wie z.B. user.class.php?

Kann mir da jemand ein Biespiel geben? :)
02/01/2013 16:04 Synatex#6
Erben. Hauptobjekt ist die CMS Klasse. Diese kriegt dann das Datenbankobjekt übertragen, oder erbt es ebenfalls. Dann hast eine Klasse die als User-System-Wrapper dient die dann bestimmte Funktionen des "CMS" erbt und für die User-Klasse dann darstellt oder übergibt.

Somit wäre es beispielsweise:

PHP Code:
<?php

class Cms extends Db { } ...
class 
UserWrapper extends cms // Ziehe Funktionen zur bereitstellung } ...
class User extends UserWrapper { } ...

?>
Dann kommt es halt drauf an wie du mit private/public/protected spielst um zu sehen welche Methoden zur Verfügung stehen.
02/01/2013 16:23 Mikesch01#7
Das ist doch aber semantisch nicht richtig oder?

So müsste jeder Klasse von cms abgeleitet werden und cms hat ja keine gemeinsamen Eigenschaften mit der jeweiligen Klasse.

Bin grad bisschen verwirrt...
02/01/2013 16:43 Synatex#8
Dann machst dir halt einen Einsprungspunkt von der Klasse Main(). Es muss etwas geben von wo du auf alle nötigen Hilfsmittel zugreifen kannst, sonst kannst direkt das ganze mit Funktionen lösen und das dort includen wo du es brauchst..

Die Klasse CMS wird dann weiter unteilt in CMSUsers, CMSArticles, CMS... und so weiter, dass "CMS" nur als Grundgerüst dient.
02/01/2013 19:26 dowhile#9
Hi,

ich verstehe auch nicht, wieso nach Syntax ein guter Ansatz sein soll, wenn ein Benutzer im Endeffekt von der Datenbank-Klasse ableitet. So eine Vererbungshierarchie ist imho total schwachsinnig.

Eine "hat-ein"-Beziehung zwischen User und DB ist definitiv sinnvoller als eine "ist-ein"-Beziehung - denn der Benutzer ist keine Datenbank ... (Oder irgendwie so argumentiert). Zudem würde Syntax's Lösungsansatz das Problem, dass alle Objekte das gleiche DB-Objekt nutzen sollen, nicht (... denn mit seinem Ansatz ist fast jedes Objekt ein eigenes DB-Objekt).

1. DB als Singleton: Du kannst auf das DB-Objekt von überall zugreifen. Nachteil: Viele Klassen sind fest an das Datenbank-Objekt gebunden. Es ist nicht mögliche, einzelne Komponente ohne eine richtige Datenbank zu testen.

2. DI: Du übergibst das DB-Objekt an jedes Objekt (via Setter oder direkt dem Konstruktor). Wenn du für die DB-Klasse eine Schnitstelle definierst kannst du sie so austauschen.
Dazu kannst du noch einen DI Container nutzen: Das ist ein Framework, das für dich Objekte anlegt und dabei die Abhängigkeiten dieser prüft und auflöst. Ich weiß nicht, welche Frameworks es dafür in PHP gibt, aber in Java mit Guice könnte das beispielsweise so aussehen (Methodennamen können falsch sein, ich habe die nicht im Kopf):

Quote:
class MyService implements MyServiceInterface {}
class MyComponent {
@Inject private MyServiceInterface theService;
}

Injector guice = new Injector();
guice.bind(MyService.class).to(MyServiceInterface. class);

MyComponent c = guice.newInstance(MyComponent.class);
Guice erkennt die @Inject-Annotation automatisch und löst die Abhängigkeit auf; mit zusätzlichen Annotation kann bestimmt werden, dass von einem Service immer das gleiche Objekt genutzt werden soll.

Viele DI Container lagern die Informationen über die Abhängigkeiten auch in Konfigurationsdateien aus (z.B. Spring).

3. Service Locator Pattern: Jede Klasse kennt irgendwie einen Service Locator, der Abhängigkeiten auflösen kann. Quasi eine API wie

Quote:
DatabaseInterface db = locator.get(DatabaseInterface.class);
Der konkrete Komponent muss so nicht wissen, woher dieses Objekt stammt. Das PHP Framework "APF" löst das auch in etwa so - dort verfügt jeder Service (und Controller etc.) über eine Methode "getServiceObject(name:Str)", die eine Instanz des Services liefert.

Am besten zu schaust dir an, wie richtige Frameworks das lösen (Yii, Symfony etc.).