Najlepsza praktyka: PHP magiczne metody set and get [duplicate]
Możliwy duplikat:
czy magiczne metody są najlepszą praktyką w PHP?
Są to proste przykłady, ale wyobraź sobie, że masz więcej właściwości niż dwie w swojej klasie.
Jaka byłaby najlepsza praktyka?A) używanie _ _ get I _ _ set
class MyClass {
private $firstField;
private $secondField;
public function __get($property) {
if (property_exists($this, $property)) {
return $this->$property;
}
}
public function __set($property, $value) {
if (property_exists($this, $property)) {
$this->$property = $value;
}
}
}
$myClass = new MyClass();
$myClass->firstField = "This is a foo line";
$myClass->secondField = "This is a bar line";
echo $myClass->firstField;
echo $myClass->secondField;
/* Output:
This is a foo line
This is a bar line
*/
B) za pomocą tradycyjnych seterów i getterów
class MyClass {
private $firstField;
private $secondField;
public function getFirstField() {
return $this->firstField;
}
public function setFirstField($firstField) {
$this->firstField = $firstField;
}
public function getSecondField() {
return $this->secondField;
}
public function setSecondField($secondField) {
$this->secondField = $secondField;
}
}
$myClass = new MyClass();
$myClass->setFirstField("This is a foo line");
$myClass->setSecondField("This is a bar line");
echo $myClass->getFirstField();
echo $myClass->getSecondField();
/* Output:
This is a foo line
This is a bar line
*/
W tym artykule: http://blog.webspecies.co.uk/2011-05-23/the-new-era-of-php-frameworks.html
Autor twierdzi że używanie magicznych metod nie jest dobrym pomysłem:
Ale chciałbym poznaj więcej opinii na ten temat.Po pierwsze, wtedy bardzo popularne było używanie magicznych funkcji PHP (__get, _ _ call itp.). Nie ma z nimi nic złego Od pierwszego spojrzenia, ale są naprawdę bardzo niebezpieczne. Sprawiają, że API są niejasne, autouzupełnianie niemożliwe i co najważniejsze są powolne. Przykładem użycia dla nich było zhakowanie PHP, aby zrobić rzeczy, których nie chciał. I zadziałało. Ale sprawił, że stało się coś złego.
9 answers
Byłem dokładnie w Twoim przypadku w przeszłości. A ja wybrałam magiczne metody.
To był błąd, ostatnia część twojego pytania mówi wszystko:
- to jest wolniejsze (niż gettery/settery)
- nie ma żadnego automatycznego uzupełniania (a to jest poważny problem), oraz zarządzanie typami przez IDE do refaktoryzacji i przeglądania kodu (pod Zend Studio/PhpStorm może to być obsługiwane za pomocą adnotacji
@property
phpdoc, ale wymaga to utrzymuj je: dość boli) - Dokumentacja (phpdoc) nie pasuje do tego, jak powinien być używany Twój kod, A przeglądanie twojej klasy nie przynosi zbyt wielu odpowiedzi. To jest mylące.
- dodane po edycji: posiadanie getterów dla właściwości jest bardziej zgodne z" rzeczywistymi " metodami gdzie
getXXX()
nie tylko zwraca własność prywatną, ale robi prawdziwą logikę. Masz to samo imię. Na przykład masz$user->getName()
(zwraca własność prywatną) i$user->getToken($key)
(obliczony). Dzień, w którym twój getter dostaje więcej niż getter i musi zrobić trochę logiki, wszystko jest nadal spójne.
Wreszcie, i to jest największy problem IMO: to jest magia. A magia jest bardzo, bardzo zła, ponieważ trzeba wiedzieć, jak działa magia, aby ją właściwie wykorzystać. To jest problem, który spotkałem w zespole: każdy musi zrozumieć magię, nie tylko Ty.
Gettery i setery to ból do pisania (nienawidzę ich), ale są tego warte.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-30 06:41:19
Musisz używać magii tylko wtedy, gdy obiekt jest rzeczywiście "magiczny". Jeśli masz klasyczny obiekt o stałych właściwościach, użyj setterów i getterów, działają dobrze.
Jeśli twój obiekt ma właściwości dynamiczne na przykład jest częścią warstwy abstrakcji bazy danych, a jego parametry są ustawiane w czasie wykonywania, to rzeczywiście potrzebujesz magicznych metod dla wygody.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-06 12:59:48
Używam __get
(i public properties) w miarę możliwości, ponieważ sprawiają, że kod jest o wiele bardziej czytelny. Porównaj:
Ten kod jednoznacznie mówi, co robię:
echo $user->name;
Ten kod sprawia, że czuję się głupio, czego nie lubię:
function getName() { return $this->_name; }
....
echo $user->getName();
Różnica między nimi jest szczególnie oczywista, gdy uzyskujesz dostęp do wielu właściwości jednocześnie.
echo "
Dear $user->firstName $user->lastName!
Your purchase:
$product->name $product->count x $product->price
"
I
echo "
Dear " . $user->getFirstName() . " " . $user->getLastName() . "
Your purchase:
" . $product->getName() . " " . $product->getCount() . " x " . $product->getPrice() . " ";
Czy $a->b
naprawdę powinno zrobić coś lub po prostu zwrócić wartość jest odpowiedzialność kallee. Dla wywołującego, $user->name
i $user->accountBalance
powinny wyglądać tak samo, chociaż te ostatnie mogą wiązać się ze skomplikowanymi obliczeniami. W moich klasach danych używam następującej małej metody:
function __get($p) {
$m = "get_$p";
if(method_exists($this, $m)) return $this->$m();
user_error("undefined property $p");
}
Gdy ktoś wywoła $obj->xxx
i klasa ma zdefiniowaną get_xxx
, ta metoda zostanie wywołana domyślnie. Możesz więc zdefiniować getter, jeśli tego potrzebujesz, zachowując jednolity i przejrzysty interfejs. Jako dodatkowy bonus zapewnia elegancki sposób zapamiętywania obliczenia:
function get_accountBalance() {
$result = <...complex stuff...>
// since we cache the result in a public property, the getter will be called only once
$this->accountBalance = $result;
}
....
echo $user->accountBalance; // calculate the value
....
echo $user->accountBalance; // use the cached value
Podsumowując: php jest dynamicznym językiem skryptowym, używaj go w ten sposób, nie udawaj, że robisz Javę lub C#.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-04 11:23:00
Robię mieszankę odpowiedzi edema i Twojego drugiego kodu. W ten sposób, mam korzyści z common getter / setters(uzupełnianie kodu w IDE), łatwość kodowania, jeśli chcę, wyjątki ze względu na nieistniejące właściwości (świetne do odkrywania literówek: $foo->naem
zamiast $foo->name
), właściwości tylko do odczytu i Właściwości złożone.
class Foo
{
private $_bar;
private $_baz;
public function getBar()
{
return $this->_bar;
}
public function setBar($value)
{
$this->_bar = $value;
}
public function getBaz()
{
return $this->_baz;
}
public function getBarBaz()
{
return $this->_bar . ' ' . $this->_baz;
}
public function __get($var)
{
$func = 'get'.$var;
if (method_exists($this, $func))
{
return $this->$func();
} else {
throw new InexistentPropertyException("Inexistent property: $var");
}
}
public function __set($var, $value)
{
$func = 'set'.$var;
if (method_exists($this, $func))
{
$this->$func($value);
} else {
if (method_exists($this, 'get'.$var))
{
throw new ReadOnlyException("property $var is read-only");
} else {
throw new InexistentPropertyException("Inexistent property: $var");
}
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-31 08:09:10
Głosuję za trzecim rozwiązaniem. Używam tego w moich projektach i Symfony też używa czegoś takiego:
public function __call($val, $x) {
if(substr($val, 0, 3) == 'get') {
$varname = strtolower(substr($val, 3));
}
else {
throw new Exception('Bad method.', 500);
}
if(property_exists('Yourclass', $varname)) {
return $this->$varname;
} else {
throw new Exception('Property does not exist: '.$varname, 500);
}
}
W ten sposób Masz automatyczne gettery (możesz też pisać settery) i musisz pisać nowe metody tylko wtedy, gdy istnieje specjalny przypadek dla zmiennej członkowskiej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-31 07:44:19
Powinieneś użyć stdClass jeśli chcesz mieć członków magic, jeśli napiszesz klasę-określ, co ona zawiera.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-31 07:38:50
Najlepszą praktyką byłoby stosowanie tradycyjnych getterów i seterów, ze względu na introspekcję lub refleksję. W PHP (podobnie jak w Javie) istnieje sposób na uzyskanie nazwy metody lub wszystkich metod. Takie coś zwróci "_ _ get "w pierwszym przypadku i "getFirstField", "getSecondField" w drugim (Plus setery).
Więcej na ten temat: http://php.net/manual/en/book.reflection.php
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-31 07:43:24
Teraz wracam do setterów i getterów, ale umieszczam również getterów i seterów w magicznym methos _ _ get I _ _ set. W ten sposób mam domyślne zachowanie, gdy to robię
$class - > var;
To po prostu wywoła getter, który ustawiłem w _ _ get. Normalnie po prostu użyję gettera bezpośrednio, ale nadal istnieją przypadki, w których jest to po prostu prostsze.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-31 09:18:18
Drugi przykład kodu jest o wiele bardziej odpowiedni, ponieważ przejmujesz pełną kontrolę nad danymi, które są przekazywane class
.
Są przypadki, w których __set
i __get
są przydatne, ale nie w tym przypadku.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-17 04:43:38