PHP Klassen $this

selberbauer

Captain
Registriert
Juni 2009
Beiträge
3.604
Hallo,
ich habe immernoch Probleme, wann man $this einsetzt und was man dabei zu beachten hat.

Ich wollte eine neue Klasse anlegen, welche die Login Daten von mysqli übernimmt, in einer privaten Funktion eine Tabelle ggf. anlegt und dannach mit einer öffentlichen Funktion die Möglichkeit bietet einen neuen Benutzer hinzuzufügen.

PHP:
class user_management extends mysqli {
	public function __construct($host, $user, $password, $database) {
		parent::__construct($host, $user, $password, $database);
		if(mysqli_connect_errno()) {
			echo 'Fehler bei Verbindung';
			echo mysqli_connect_err();
			return false;
		} else {
			return true;
		}
	}
	
	var $sql_table = 'CREATE TABLE IF NOT EXISTS users	(ID INT(11) AUTO_INCREMENT PRIMARY KEY,
	user VARCHAR(50) NOT NULL,	hash VARCHAR(512) NOT NULL,	email VARCGAR(100) NOT NULL, UNIQUE(user))';
	
	private function create_table($sql_table) {
		if ($this->query($sql_table)) {
			return true;
		} else {
			return false;
		}
	}
	
	$this->create_table($this->sql_table);
	
	public function new_user($new_user, $new_pass) {
		$sql_check = 'SELECT COUNT(*) FROM users WHERE user=? AND hash=?';
		if(!($this->prepare($sql_check))) {
			 trigger_error('Could not prepare statement!',E_USER_ERROR);
			 return false;
		}
		$hash = hash('SHA512', $new_pass);
		$this->bind_param('ss', $new_user, $hash)
		$this->execute();
		if($this->errno) {
			 trigger_error('Could not prepare statement!',E_USER_ERROR);
			 return false;
		}
		$this->bind_result($matches);
		$this->fetch();
		$this->close();
		echo $new_user . 'wurde mit' . $hash . 'angelegt';
		return ($matches == 1);
	}
}

$db = user_management('localhost', 'user', 'wambo', 'test');
$db->new_user('klaus', 'ente');
 
Was hat der Code ausserhalb der Funktionen zu suchen?

$this->create_table($this->sql_table);

Das gehört da nicht hin.

Achja, und ein Konstruktor kann nix returnen, nur explodieren (throw)

und anstatt so sachen:

PHP:
if ($this->query($sql_table)) {
return true;
} else {
return false;
}

geht ja auch einfach return $this->query($sql_table);
 
Zuletzt bearbeitet:
$this ist der Zeiger auf das eigene Objekt innerhalb der Klasse. Aber es wird wohl nicht funktionieren, weil das Problem besteht was bu1137 nennt. Frage mich gerade sowieso, warum der PHP-Parser dir das nicht um die Ohren wirft...
Code:
Parse error: syntax error, unexpected T_VARIABLE, expecting T_FUNCTION in datei.php on line 22
 
Zuletzt bearbeitet:
this ist eine Referenz auf das Objekt, aus dem heraus this aufgerufen wird.
Ich hoffe was Objektorientiert ist, ist bekannt, wenn nicht, kurz googeln. (Kurz gesagt, alles basiert auf objekten).
Wenn ich also eine Klasse habe die "Einkaufswagen" heißt, und eine Funktion welche die Anzahl der im "Einkaufswagen" befindlichen Artikel ausgeben soll, dann bezieht sich diese Anzahl auf einen speziellen Einkaufswagen, nicht auf alle.
(Einkaufswagen hat einen im Objekt befindlichen Zähler)
In diesem Fall wird also this verwendet, um aus der spezifischen Objektinstanz die Artikelzahl heraus zu finden.

Ich hoffe die Erklärung macht es einigermaßen deutlich.
In deinem Objekt referenziert $this also die eigene Klasse, user_management.
$this->create_table ruft also user_management.create_table auf, und zwar das "create_table", welches sich in der aktuellen Objektinstanz befindet.

MfG
Damon
 
@alle Danke für die Erklärung mit $this ;)

Naja ich habe den Code in die Klasse geschmissen, weil die Klasse selbst prüfen soll, ob die Tabelle bereits vorhanden ist. Extra aufrufen wäre ja irgendwie stark redundant, besonders, weil die funktion new_user von create_table abhängt.

Von der Struktur her wäre das doch eigentlich sinnvoll.
Ich habe eine Klasse die alle Funktionen einer Benutzerverwaltung enthält und diese Funktionen setzen nunmal eine Funktionsfähige Tabelle vorraus.
Oder sollte ich das Anlegen von Tabellen eher funktional komplett trennen, sodass eine extra Klasse bzw. ein extra Script alle nötigen Tabellen anlegt?
 
Ich würde dir davon abraten von der Klasse mysqli zu erben. Das macht schlicht keinen Sinn. Vererbung ist dazu gedacht um die Oberklasse zu spezialisieren oder zu modifzieren. Ich würde es hier deutlich sinnvoller finden wenn du eine Klasse "user_management" erstellst, die von gar keiner anderen Klasse erbt und
im Konstruktor eine Referenz auf ein mysqli-Objekt übergeben bekommt. Das speicherst du dann in eine Klassenvariable (z.B. $this->db) und nutzt diese dann in allen Methoden der Klasse für Datenbankaufrufe.
Das hat besonders dann einen großen Vorteil wenn du noch andere Klasse zum Management von irgendwelchen Daten hast, denn du kannst so die gleiche Datenbankverbindung für alle verwenden.
 
Ich würde dir davon abraten von der Klasse mysqli zu erben. Das macht schlicht keinen Sinn. Vererbung ist dazu gedacht um die Oberklasse zu spezialisieren oder zu modifzieren
Sowas wie "class car" zu "class sportscar, class van, ...."?

im Konstruktor eine Referenz auf ein mysqli-Objekt übergeben bekommt. Das speicherst du dann in eine Klassenvariable (z.B. $this->db) und nutzt diese dann in allen Methoden der Klasse für Datenbankaufrufe
Stimmt das so?
PHP:
<?php

$host     = 'localhost';
$username = 'user';
$password = 'wambo';
$database = 'test';

$db = new mysqli($host, $username, $password, $database);
$user_management = new user_management($db);

$user_management->new_user('bodo', 'ente');
class user_management {
	public function __construct($db) {}

	var $sql_table = 'CREATE TABLE IF NOT EXISTS users	(ID INT(11) AUTO_INCREMENT PRIMARY KEY,
	user VARCHAR(50) NOT NULL,	hash VARCHAR(512) NOT NULL,	email VARCGAR(100) NOT NULL, UNIQUE(user))';
	private function create_table($sql_table) {
		$db->query($sql_table);
	}
	
	$this->create_table($sql_table);
	
	public function new_user($new_user, $new_pass) {
		$sql_check = 'SELECT COUNT(*) FROM users WHERE user=? AND hash=?';
		if(!($db->prepare($sql_check))) {
			 trigger_error('Could not prepare statement!',E_USER_ERROR);
			 return false;
		}
		$hash = hash('SHA512', $new_pass);
		$db->bind_param('ss', $new_user, $hash);
		$db->execute();
		if($db->errno) {
			 trigger_error('Could not prepare statement!',E_USER_ERROR);
			 return false;
		}
		$db->bind_result($matches);
		$db->fetch();
		$db->close();
		echo $new_user . 'wurde mit' . $hash . 'angelegt';
		return ($matches == 1);
	}
}

?>
Das hat besonders dann einen großen Vorteil wenn du noch andere Klasse zum Management von irgendwelchen Daten hast, denn du kannst so die gleiche Datenbankverbindung für alle verwenden.
Gerade deswegen wollte ich die Klasse eigentlich vererben, wusste nicht, dass das auch so geht...


Kannst du mir noch die vorherige Frage mit dem internen Methodenaufruf beantworten?
Von der Struktur her wäre das doch eigentlich sinnvoll.
Ich habe eine Klasse die alle Funktionen einer Benutzerverwaltung enthält und diese Funktionen setzen nunmal eine Funktionsfähige Tabelle vorraus.
Oder sollte ich das Anlegen von Tabellen eher funktional komplett trennen, sodass eine extra Klasse bzw. ein extra Script alle nötigen Tabellen anlegt?

Gruß
 
Zuletzt bearbeitet:
Du kannst immernoch nicht einfach zwischen den Klassenfunktionen irgendwelchen Code stecken. Das ist nach wie vor fehl am Platz:

$this->create_table($sql_table);

Das wird nie ausgeführt und ist einfach nur ungültig. Wenn du willst, dass create_table() beim Erstellen vom Objekt ausgeführt wird, müsstest du es in den Konstruktor tun. Wobei ich das keinesfalls machen würde.

Nebenbei braucht "var $sql_table" sicherlich keine Klassenvariable zu sein. Pack das wennschon in die create_table funktion.

Existierende Tabellen sind Voraussetzung. Das Erstellen solltest du woanders regeln. Ist ja nicht so, als müsstest du das alle 5 Minuten machen...
 
Zuletzt bearbeitet:
Jop danke :D
werde dann eine weitere Klasse schreiben, welche die Tabelle einrichtet.

Ein letztes Mal will ich euch noch belästigen:
In meiner Klasse liegt ein Fehler mit
PHP:
if(!($db->prepare($sql_check))) {
			 trigger_error('Could not prepare statement!',E_USER_ERROR);
			 return false;
		}
vor.

PHP Notice: Undefined variable: db in /home/bodo/Projekte/lang/PHP/erebos/lib.php on line 7
PHP Fatal error: Call to a member function prepare() on a non-object in /home/bodo/Projekte/lang/PHP/erebos/lib.php on line 7
 
... public $db; in der Klasse sollte speichern tuts nicht.... dieses rätsel raten bringt leider edukativ noch produktiv viel...
 
Das Erstellen der Tabellen sollte in dem Code am besten gar nicht enthalten sein, weil es Administrationsrechte für den betreffenden MySQL-User benötigt. Davon solltest du grundsätzlich Abstand nehmen. Schreib die CREATE TABLE lieber in einer separaten SQL-Datei zusammen und lad sie bei der Installation auf den MySQL-Server.

Die Implementierung aus #7 stimmt so leider nicht. Du solltest dir dringend die PHP-Dokumentation zu Klassen durchlesen (und verstehen).

Als erstes sollte eine Instanzvariable definiert werden, die dann im Konstruktor beschrieben wird. Alle anderen Memberfunktionen greifen dann auf diese Variable zu, und zwar über $this. Beispiel:

Code:
$db = new mysqli($host, $username, $password, $database);
$user_management = new user_management($db);
 
$user_management->new_user('bodo', 'ente');
class user_management {
  [COLOR="red"]private $db; // instanzvariable[/COLOR]
  public function __construct($db) {
    [COLOR="red"]$this->db = $db; // instanzvariable initialisieren[/COLOR]
  }

  public function new_user($new_user, $new_pass) {
    $sql_check = 'SELECT COUNT(*) FROM users WHERE user=? AND hash=?';
    if(!([COLOR="Red"]$this->db[/COLOR]->prepare($sql_check))) {
      trigger_error('Could not prepare statement!',E_USER_ERROR);
      return false;
    }
  ....
  }

  ...
  
}

Instanzvariablen sollten möglichst immer private oder protected sein. $this brauchst du übrigens immer dann, wenn du in der Methode einer Klasse auf eine Instanzvariable der Klasse zugreifen willst oder eine Methode aus der Klasse aufrufen willst.
 
Zurück
Oben