OOP - Variable global in Klasse benutzen

jannicars

Erfahrenes Mitglied
Hallo,

Ich bin gerade dabei mein aktuelles Projekt OOP zu machen.
Jetzt bin ich schon beim ersten Problem angelangt.

Als erstes mal ein Beispiel Quellcode:
PHP:
<?php
class class1{
	public function load(){
		$test = "test";
		return $test;
	}
}

class class2 extends class1{
	public function __construct(){
		$load = $this->load();
		echo "Construct Echo:" . $load;
		$this->function1();
	}
	public function function1(){
		echo "Function1 Echo:" . $load;
	}
}

new class2;
?>

Nun meine Frage: wie kann ich $load in meiner class2 Globalisieren?
Also dass ich nicht immer nochmals die function2 in jeder Funktion nochmals aufrufen muss?
(function2 ist ein SQL-Query - Es wäre unsinnig mit 20 Funktionen 20 Querys zu erzeugen)

So würde es klappen; find ich aber nicht so elegant, da ich die variable zu jeder Funktion immer mitübergeben müsste:
PHP:
<?php
class class1{
	public function load(){
		$test = "test";
		return $test;
	}
}

class class2 extends class1{
	public function __construct(){
		$load = $this->load();
		echo "Construct Echo:" . $load;
		$this->function1($load);
	}
	public function function1($load){
		echo "Function1 Echo:" . $load;
	}
}

new class2;
?>

Gibt es da noch eine elegantere Lösung?
Ich hab es noch so funktioniert, hat aber auch nicht geklappt:
PHP:
<?php
class class1{
	public function load(){
		$test = "test";
		return $test;
	}
}

class class2 extends class1{
	public function __construct(){
		$load = $this->load();
		echo "Construct Echo:" . $load;
		$this->function1();
	}
	public function function1(){
        global $load;
		echo "Function1 Echo:" . $load;
	}
}

new class2;
?>
 
Zuletzt bearbeitet:
So scheint es gut zu klappen:
PHP:
<?php
class class1{
	public function load1(){
		$test = "test";
		return $test;
	}
}

class class2 extends class1{
	var $load;
	public function __construct(){
		$this->load = $this->load1();
		echo "Construct Echo:" . $this->load;
		$this->function1();
	}
	public function function1(){
		echo "Function1 Echo:" . $this->load;
	}
}

new class2;
?>

Wenn es eine bessere Möglichkeit gibt, nur her damit!
 
Genauso macht man "globale" Klassen-Variablen. Eigentlich sind das sog. Member-Variablen. Sie können entweder

- nur innerhalb der Klasse sichtbar sein (private)
- innerhalb der Klasse und allen abgeleiteten Klassen sein (protected)
- oder öffentlich sein (public)

Hier ein paar Beispiele:

private:

PHP:
<?php
class klasse1
{
  // Diese Klassenmember ist nur innerhalb dieser Klasse verfügbar
  private $member;

  public function __construct()
  {
     $this->member = 42;
  }

  public function printOutMember()
  {
    echo "In Klasse " .get_class($this) .": " . $this->member . "<br/>";
  }
}

class klasse2 extends klasse1
{
  // Diese Klassenmember ist nur innerhalb dieser Klasse verfügbar
  private $memberKlasse2;

  // Konstruktor wird überschrieben
  public function __construct()
  {
     $this->memberKlasse2 = 44;
  }

  // Print-Out-Methode wird überschrieben
  public function printOutMember()
  {
    // Das hier funktioniert nicht bzw. gibt einen leeren String aus, 
    // da auf die Elternklassen-private-Member nicht zugegriffen werden kann
    // echo $this->member;
    echo "In Klasse " .get_class($this) .": " . $this->memberKlasse2 . "<br/>";
  }
}

$a = new klasse1();
$a->printOutMember();

$b = new klasse2();
$b->printOutMember();

Protected-Member und Methoden:

PHP:
class klasse1
{
	// Diese Klassenmember ist nur innerhalb dieser Klasse und Kindsklassen verfügbar
	protected $member;

	public function __construct()
	{
		$this->member = 42;
	}

	public function printOutMember()
	{
		echo "In Klasse " .get_class($this) .": " . $this->member . "<br/>";
	}
}

class klasse2 extends klasse1
{
	// Diese Klassenmember ist nur innerhalb dieser Klasse verfügbar
	private $memberKlasse2;

	// Konstruktor wird überschrieben
	public function __construct()
	{
		// Das ist notwendig, damit der Konstruktor in der Eltern-Klasse auch aufgerufen werden kann
		parent::__construct();
		$this->memberKlasse2 = 44;
	}

	// Print-Out-Methode wird überschrieben
	public function printOutMember()
	{
		// Das hier funktioniert nicht bzw. gibt einen leeren String aus,
		// da auf die Elternklassen-private-Member nicht zugegriffen werden kann
		echo "In Klasse " .get_class($this) .": " . $this->member . "<br/>";
		// Wir können auch die Methode in der Eltern-Klasse aufrufen:
		parent::printOutMember();
		echo "In Klasse " .get_class($this) .": " . $this->memberKlasse2 . "<br/>";
	}
}

$a = new klasse1();
$a->printOutMember();

// Das funktioniert auch nicht:
//echo $a->member;

$b = new klasse2();
$b->printOutMember();
// Und das funktioniert auch nicht
//echo $b->memberKlasse2;

Öffentliche Zugriffe

PHP:
<?php
class klasse1
{
	// Diese Klassenmember ist nur innerhalb dieser Klasse und Kindsklassen verfügbar
	protected $member;

	public function __construct()
	{
		$this->member = 42;
	}

	public function printOutMember()
	{
		echo "In Klasse " .get_class($this) .": " . $this->member . "<br/>";
	}
}

class klasse2 extends klasse1
{
	// Diese Klassenmember ist global verfügbar
	public $memberKlasse2;

	// Konstruktor wird überschrieben
	public function __construct()
	{
		// Das ist notwendig, damit der Konstruktor in der Eltern-Klasse auch aufgerufen werden kann
		parent::__construct();
		$this->memberKlasse2 = 44;
	}

	// Print-Out-Methode wird überschrieben
	public function printOutMember()
	{
		// Das hier funktioniert nicht bzw. gibt einen leeren String aus,
		// da auf die Elternklassen-private-Member nicht zugegriffen werden kann
		echo "In Klasse " .get_class($this) .": " . $this->member . "<br/>";
		echo "In Klasse " .get_class($this) .": " . $this->memberKlasse2 . "<br/>";
	}
}

$a = new klasse1();
$a->printOutMember();

// Das funktioniert nicht:
//echo $a->member;

$b = new klasse2();
$b->printOutMember();
// Das hier aber schon:
echo "Im globalen Scope: " . $b->memberKlasse2 . "<br/>";

Vielleicht hilft es dir ein bisschen :-)

Wenn du fragen hast, her damit ;)
 
Zuletzt bearbeitet:
Hallo Saftmeister,

Ich verstehe zwar schon jetzt diese 3 Eigenschaften Bedeutungen, erkenne aber leider nicht den Sinn, wo ich Public, protected und private wie am sinnvollsten einsetzen söllte...?
 
Private zb dann wenn du nicht willst das Kind-Klassen diese Variable überschreiben können.

Protected wenn sie von Kind-Klassen überschrieben werden darf.

Public ist quasi komplett offen, dort kannst du sie auch ausserhalb der Klasse überschreiben:

PHP:
class test
{
   public $var1;
   protected $var2;
   private $var3;

   public function __construct(){
      $this->var1 = 'is public';
      $this->var2 = 'is protected';
      $this->var3 = 'is private';
   }

   public function getVar1(){
      echo $this->var1;
   }

   public function getVar2(){
      echo $this->var2;
   }

    public function getVar3(){
      echo $this->var3;
   }
}

$Test = new test();

echo $Test->var1; // gibt Wert der Variable zurück

echo $Test->var2; // Fehler, da Member-Variable nicht von aussen zugreifbar ist. Das selbe auch bei $this->var3

echo $Test->getVar1(); // gibt wert 'is public'
echo $Test->getVar1(); // gibt wert 'is protected'
echo $Test->getVar1(); // gibt wert 'is private'

Saftmeister hat es eigentlich schon perfekt erklärt.
 
Das kommt auf den Anwendungsfall an. Ich habe jetzt aus dem Stand kein Beispiel parat, wo man welche Variante einsetzen könnte. Außer vielleicht dem:

PHP:
<?php
/**
 * Basis-Personen-Klasse
 * 
 * Unveränderliche Werte werden privat sein
 * Veränderliche Werte werden protected sein
 * 
 * @author saftmeister
 */
class Person
{
	/**
	 * Die ID in z.B. der Datenbank
	 * 
	 * @var int
	 */
	private $id;
	
	/**
	 * Der Vorname der Person
	 * 
	 * @var string 
	 */
	private $firstName;
	
	/**
	 * Der Nachname der Person
	 * 
	 * @var string
	 */
	protected $lastName;
	
	/**
	 * Das Geburtsdatum der Person
	 * 
	 * @var DateTime
	 */
	private $birthDate;
	
	/**
	 * Die Adresse der Person
	 * 
	 * @var Address
	 * @todo Adressenklasse schreiben
	 */
	protected $address;
	
	/**
	 * Neues Objekt vom Typ Person erzeugen
	 * 
	 * @param int $id
	 * @param string $firstname
	 * @param string $lastname
	 * @param DateTime $birthdate
	 * @param Adress $address
	 * @throws Exception
	 */
	public function __construct($id, $firstname, $lastname, DateTime $birthdate, $address)
	{
		$this->id = $id;
		
		if(!$this->id)
		{
			throw new Exception('Ungültige ID!');
		}
		
		$this->firstName = $firstname;
		$this->lastName  = $lastname;
		$this->birthDate = $birthdate;
		$this->address   = $address;
	}
	
	/**
	 * Gibt die ID des Datensatzes zurück
	 * 
	 * @return int
	 */
	public function getId()
	{
		return $this->id;
	}
	
	/**
	 * Gibt den Vornamen zurück
	 * 
	 * @return string
	 */
	public function getFirstName()
	{
		return $this->firstName;
	}
	
	/**
	 * Gibt das Geburtsdatum zurück
	 * 
	 * @return DateTime
	 */
	public function getBirthDate()
	{
		return $this->birthDate;
	}
}

/**
 * Mitarbeiter-Klasse
 * 
 * @author jannicars
 */
class Employer extends Person
{
	/**
	 * Art der Mitarbeit
	 * 
	 * @var string
	 */
	private $work;
	
	/**
	 * Ein neues Objekt vom Typ Employer erzeugen
	 * 
	 * @param int $id
	 * @param string $firstname
	 * @param string $lastname
	 * @param DateTime $birthdate
	 * @param Adress $address
	 * @param string $work
	 */
	public function __construct($id, $firstname, $lastname, $birthdate, $address, $work)
	{
		// Eltern-Konstruktor aufrufen und Werte übergeben
		parent::__construct($id, $firstname, $lastname, $birthdate, $address);
		
		$this->work = $work;
	}
	
	/**
	 * Mitarbeits-Art zurück geben
	 * @return string
	 */
	public function getWork()
	{
		return $this->work;
	}
}

$saftmeister = new Employer(1, 'saft', 'meister', new DateTime('1970-01-01'), '127.0.0.1', 'Coder');

echo "ID: " . $saftmeister->getId() . "<br/>";
echo "Work: " . $saftmeister->getWork() . "<br/>";

Angenommen, die Klasse "Person" ist für dich nicht verfügbar, lediglich die öffentlichen Schnittstellen. Du kannst also maximal den Konstruktor aufrufen, um ein neues Objekt zu erzeugen und die ID abholen.

Du sollst jetzt eine Klasse "Employer" schreiben, die "Person" erweitert, auf die veränderlichen Werte darfst du schreibend und lesend zu greifen. Veränderlich bedeutet, das man die Werte jederzeit anpassen können muss.

Werte wie der Vorname, das Geburtsdatum und die ID definieren wir einfach mal unveränderlich. Daher kannst du nur über Getter auf die Werte zu greifen.

Das ganze macht vor allem dort Sinn, wo mit Klassen gearbeitet werden soll, auf die ein weiterer Programmierer (saftmeister hat die Klasse "Person" geschrieben, jannicars die Klasse "Employer") keinen Zugriff haben braucht/soll/darf.

Wie gesagt, das ist stark vom Anwendungsfall abhängig.
 
Danke für das Beispiel!

Ich werde einfach alles Public machen,
da es ja sonst keine Vorteile gibt, außer das es eingegrenzt ist.
Bringt denn das Eingrenzen was für die Sicherheit oder wie?

Und da ich die Klassen eh nur für mein eigenes Projekt benutze,
ist es doch egal und ich lass es einfach immer bei Public...?
 
Zuletzt bearbeitet:
Sicherheit - Begrenzt.
Aber es gibt manchmal Methoden innerhalb von Klassen, die öffentlich keinen Sinn machen oder gar einen Fehler generieren wenn sie von Ausserhalb aufgerufen wird.

Gut, du programmierst für dich alleine. Dann gehts mit public. Aber wenn du mit anderen zusammen programmierst oder deinen Code weiter geben willst, so kannst du mit diesen Unterscheidungen dem Anwender der Klasse mitgeben welche Methoden für ihn sind und welche nicht.

Nimm als Beispiel ein Auto. Der Anlasser ist public. Den kann jeder anwenden. Mit dieser Methode (das drehen des Zündschlüssels) werden im Auto aber diverse weitere Methoden aufgerufen (einlassen von Benzin, zünden, ankurbeln etc.) All diese Methoden sind private, da du sie von Aussen nicht anwenden kannst.
 
Es ist vor allem für dich als Entwickler gedacht.

Eine gut durchdachte Klassen-Architektur verringert Fehlerquellen. Angenommen, du hast zwei Klassen, beide haben nix mit einerander gemeinsam, außer einer public Membervariablen, die zufällig in beiden Klassen gleich heißt. In einem unachtsamen Moment schreibst du statt $a->membervar ein $b->membervar. Dann gehst du 2 Tage auf die Suche nach dem Fehler, weil das nicht unbedingt offensichtlich ist.

Zugegeben, das könnte natürlich auch mit Settern passieren.

Wenn du allerdings Member als private deklarierst, die nicht unbedingt von außen erreichbar sein müssen, förderst du deine eigene Hirnhygiene. Das ist ein nicht zu unterschätzendes Stil-Mittel.

Sei's drum. Wenn du das public machen willst, weil es dir damit erstmal leichter fällt, dann mach es so. Ab einem gewissen Level, wenn du schon OOP gut beherrschst, wirst du es freiwillig anwenden ;)

Aber ich muss entschieden protestieren: Egal ist es nicht! Wenn es egal wäre, hätte man die drei Modifizierer nicht einführen brauchen :)

Spätestens bei Singleton- oder Factory-Pattern wirst du merken, das es gut ist, sowas zu haben.

Und ja, es hat was mit Sicherheit zu tun. Damit steuerst du Zugriffsmodi auf Member-Variablen und Methoden.

Ich bin mir sicher, das du es eines Tages verwenden wirst :-)
 
Zurück