Parantatatam
mag Cookies & Kekse
Guten Tag Tutorianer,
ich habe gerade ein kleines, vielleicht sogar großes, Problem mit den magischen Methoden __set() und __get(). Warum, dass erkläre ich euch jetzt: ich arbeite momentan an einem ActiveRecord-Framework und noch momentaner an der Modelklasse. Dabei gibt es sogenannte Setter und Getter, mit welchen man die Eigenschaften eines Datensatzes abfragen kann und auch verändern kann. Soweit ist das kein Problem, allerdings soll man auch die Möglichkeit haben, dass beispielsweise beim Speichern eines Kennwortes dieses gleich beim Festlegen in einen SHA1-Hash umwandeln. Das ist auch nicht das Problem, denn das erledige ich über Methoden, welche mit "set_" oder "get_" anfangen und dann der Name der Eigenschaft folgt. Jetzt kommt aber das Problem: will man nun gleich die Eigenschaft mit dem gleichen Namen überschreiben, so wird das in den meisten Frameworks darüber gelöst, dass man zwei weitere Methoden, write_attribute() und read_attribute(), hat mit welchen man den Wert überschreiben kann. Das will ich nicht, sondern ich will die magischen Methoden von PHP auch an dieser Stelle verwenden können, nur leider funktioniert dies nur halbherzig und ohne meinerseits erkenntliche Logik. Vielleicht seht ihr wo der Fehler liegt.
So wird es meistens gelöst:
So will ich es lösen:
Was ich bisher habe:
Was erledigen die einzelnen Klassen?
Wenn ein Attribut aufgerufen wird, zu dem eine Settermethode existiert, so werden die Werte an die entsprechende Settermethode weitergeleitet. Da diese auch die Methode __set() verwendet, wird vorher markiert, dass gerade eine solche Methode aufgerufen wurde. Das steckt in der Eigenschaft self::$temp. Falls self::$temp wahr ist, wird mit der Eigenschaft wie mit einer normalen Variable umgegangen und sie in der Eigenschaft self::$attributes gespeichert. Danach wird die Eigenschaft self::$temp wieder als falsch markiert. Soweit die Theorie - es funktioniert nur nicht.
PS: Auch wenn es um __set() und __get() geht, so möchte ich mich vorerst nur auf die Methode __set() beschränken.
ich habe gerade ein kleines, vielleicht sogar großes, Problem mit den magischen Methoden __set() und __get(). Warum, dass erkläre ich euch jetzt: ich arbeite momentan an einem ActiveRecord-Framework und noch momentaner an der Modelklasse. Dabei gibt es sogenannte Setter und Getter, mit welchen man die Eigenschaften eines Datensatzes abfragen kann und auch verändern kann. Soweit ist das kein Problem, allerdings soll man auch die Möglichkeit haben, dass beispielsweise beim Speichern eines Kennwortes dieses gleich beim Festlegen in einen SHA1-Hash umwandeln. Das ist auch nicht das Problem, denn das erledige ich über Methoden, welche mit "set_" oder "get_" anfangen und dann der Name der Eigenschaft folgt. Jetzt kommt aber das Problem: will man nun gleich die Eigenschaft mit dem gleichen Namen überschreiben, so wird das in den meisten Frameworks darüber gelöst, dass man zwei weitere Methoden, write_attribute() und read_attribute(), hat mit welchen man den Wert überschreiben kann. Das will ich nicht, sondern ich will die magischen Methoden von PHP auch an dieser Stelle verwenden können, nur leider funktioniert dies nur halbherzig und ohne meinerseits erkenntliche Logik. Vielleicht seht ihr wo der Fehler liegt.
So wird es meistens gelöst:
PHP:
function set_password($password) {
$this->write_attribute('password', $password);
}
So will ich es lösen:
PHP:
function set_password($password) {
$this->password = $password;
}
Was ich bisher habe:
PHP:
class XtModelStorage {
private static $storage = array();
public static function setGetter($model, array $attributes) {
if(!isset(self::$storage[$model]['getter']))
self::$storage[$model]['getter'] = $attributes;
}
public static function setSetter($model, array $attributes) {
if(!isset(self::$storage[$model]['setter']))
self::$storage[$model]['setter'] = $attributes;
}
public static function getGetter($model) {
if(isset(self::$storage[$model]['getter']))
return self::$storage[$model]['getter'];
return null;
}
public static function getSetter($model) {
if(isset(self::$storage[$model]['setter']))
return self::$storage[$model]['setter'];
return null;
}
public static function hasGetter($model, $name) {
return (isset(self::$storage[$model]['getter']) && in_array($name, self::$storage[$model]['getter']));
}
public static function hasSetter($model, $name) {
return (isset(self::$storage[$model]['setter']) && in_array($name, self::$storage[$model]['setter']));
}
public static function getList() {
return self::$storage;
}
}
class XtModel {
private static $attributes = array();
private static $temp = false;
final public function __construct() {
$setter = array();
$getter = array();
$methods = XtClass::create(get_called_class())->getMethods();
foreach($methods as $method) {
if($method->name[0] === '_')
continue;
@list($prefix, $attribute) = explode('_', $method->name, 2);
if($prefix === 'set')
$setter[] = $attribute;
elseif($prefix === 'get')
$getter[] = $attribute;
}
XtModelStorage::setGetter(get_called_class(), $getter);
XtModelStorage::setSetter(get_called_class(), $setter);
}
final public function __set($attribute, $value) {
$called = get_called_class();
if(!self::$temp && XtModelStorage::hasSetter($called, $attribute)) {
self::$temp = true;
$this->{'set_' . $attribute}($value);
return;
}
self::$attributes[$called][$attribute] = $value;
self::$temp = false;
}
final public function __get($attribute) {
$called = get_called_class();
return self::$attributes[$class][$attribute];
}
}
class Test extends XtModel {
function set_password($password) {
$this->password = sha1($password);
}
function set_username($username) {
$this->username = strlen($username);
}
}
Was erledigen die einzelnen Klassen?
- Klasse "XtModelStorage" speichert alle Getter- und Settermethoden von Klassen, welche von der Klasse "XtModel" erben
- Klasse "XtModel" enthält die gesamte Logik des Models, lädt also die Getter- und Settermethoden, speichert sie. Außerdem enthält es die Methoden __set() und __get()
- Klasse "Test" ist nur ein Beispiel
Wenn ein Attribut aufgerufen wird, zu dem eine Settermethode existiert, so werden die Werte an die entsprechende Settermethode weitergeleitet. Da diese auch die Methode __set() verwendet, wird vorher markiert, dass gerade eine solche Methode aufgerufen wurde. Das steckt in der Eigenschaft self::$temp. Falls self::$temp wahr ist, wird mit der Eigenschaft wie mit einer normalen Variable umgegangen und sie in der Eigenschaft self::$attributes gespeichert. Danach wird die Eigenschaft self::$temp wieder als falsch markiert. Soweit die Theorie - es funktioniert nur nicht.
PS: Auch wenn es um __set() und __get() geht, so möchte ich mich vorerst nur auf die Methode __set() beschränken.