Autor Zpráva
na1k
Profil
Začínám se hlouběji zajímat o OOP a mám takovouto myšlenku: chci aby se k vlastnostím tříd nedalo přistupovat přímo (třebaže jsou public) pomocí $trida->promenna, ale pouze pomocí metod $trida->getPromenna anebo $trida->setPromenna ... zjistil jsem že by to mělo jít pomocí magických metod - vytvořím si třídu, kterou budou všechny ostatní třídy dědit a tato třída bude definovat __get a __set, címž budu moci kontrolovat přístup k proměnným.
Nevšimnul jsem si ale jedné "drobnosti" - __get a __set se spouštějí jenom v případě, že daná proměnná není definovaná, a to je problém, protože potřebuju mít kontrolu nad přístupem do VŠECH proměnných (kontrolovat přístup do nedefinovaných je vcelku zbytečné) :-(
Napadá někoho jak toto řešit?

Funkci pro __get mám zkopírovanou z manuálu (pro zkoušení) a bohužel se opravdu spouští jenom při volání nedefinované proměnné :-(
public function __get($nm)
    {
        echo "Getting [$nm]\n";

        if (isset($this->x[$nm])) {
            $r = $this->x[$nm];
            print "Returning: $r\n";
            return $r;
        } else {
            echo "Nothing!\n";
        }
    }
Mastodont
Profil
Napadá někoho jak toto řešit?

Nedefinovat ve třídě na tvrdo vůbec žádnou vlastnost.
BetaCam
Profil
chci aby se k vlastnostím tříd nedalo přistupovat přímo (třebaže jsou public) pomocí $trida->promenna, ale pouze pomocí metod $trida->getPromenna anebo $trida->setPromenna

Asi sem ignorant na OOP, ale nějak nechápu důvod tohoto opatření. :)
na1k
Profil
A já začátečník, takže nedokážu přesně vysvětlit jaké to má výhody :)) Z mého pohledu je přístup tak nějak "čistší" a navíc ho mám plně pod kontrolou (chtěl bych mít :-p). Jinak na tuto myšlenku jsem narazil na nejedné stránce o OOP a tzv. getter & setter ... a pod článkem byla taky rozsáhlá diskuze, kde se dohadovali odpůrci a příznivci takového řešení :-)
Každopádně jsem si to chtěl vyzkoušet a sám zjistit, nakolik by mně to vyhovovalo .... tak či tak to nezjistím, protože to nějak nechce fungovat.

Nedefinovat ve třídě na tvrdo vůbec žádnou vlastnost.

Takhle by to sice šlo, ale zase bych musel všechny proměnné nastavovat v konstruktoru, což mně přijde jako ne zrovna nejlepší řešení (opět nemám důvod, jenom takový divný pocit) ... není nějaké "čistší" řešení? Prostě definovat proměnné v úvodu třídy a a pak jenom přepsat funkci pro přístup ke VŠEM proměnným...
BetaCam
Profil
na1k
Z mého pohledu je přístup tak nějak "čistší" a navíc ho mám plně pod kontrolou (chtěl bych mít :-p).

No nevim mě to z mého pohledu moc čisté nepřijde, ale jak sem řekl sem asi ignorant. Přijde mi divný bránit přímému přístupu k public vlastnostem. Pokud budu chtít tomuto přístupu zabránit nebudu přece vlastnost nastavovat jako public, ale dám jí třeba jako private. Samotný prístup k vlastnosti si pak můžu udělat jak já chci na úrovni metod v samotné třídě. Proste mi nejak nesedí ta myšlenka omezování public vlastnosti.

Jinak na tuto myšlenku jsem narazil na nejedné stránce o OOP a tzv. getter & setter ... a pod článkem byla taky rozsáhlá diskuze, kde se dohadovali odpůrci a příznivci takového řešení :-)

Mohl by si úvédst link na ten článek rád bych si ho přečetl. Děkuju.
na1k
Profil
něco o tom je tady

...a když o tom teď přemýšlím tak vlastně nevím co je lepší, každopádně mám v hlavě co se týče OOP pěkný zmatek :-( Něco málo o tom vím, ale to nové pojetí od php 5 mě mate ... a všema doporučovaný seriál na Intervalu tomu taky nepomohl...
Mastodont
Profil
BetaCam
Přijde mi divný bránit přímému přístupu k public vlastnostem.

Get/set metody neslouží primárně k tomu, aby bylo možné volat nedefinované properties (jak chce na1k), ale ke spouštění kódu při čtení nebo změně takové vlastnosti.

Jestliže nějakou property nadefinuješ přímo jako public, tak ji můžeš jakkoli zvenčí měnit - což ovšem ve spoustě případů je na prd, protože potřebuješ třeba omezit povolený rozsah hodnot. No a tady se právě hodí __set, protože v jejím kódu můžeš zkontrolovat předanou hodnotu.

__set obecně umožňuje spustit jakýkoli kód při nastavení hodnoty vlastnosti - to se dá v mnoha případech využít. Stejně tak read-only public property uděláš jen přes get/set metody.
BetaCam
Profil
Mastodont
Jestliže nějakou property nadefinuješ přímo jako public, tak ji můžeš jakkoli zvenčí měnit - což ovšem ve spoustě případů je na prd, protože potřebuješ třeba omezit povolený rozsah hodnot.

Otázka je jestli v takovejchle případech ji budeš definovat jako public. Pokud hned o začátku budeš vědět, že sní potřebuješ dělat nějaké operace můžeš se podle toho zařídit.

class Test {
   private $x;

   public function __construct() {}

   public function setX($externalX) {
      if($externalX < 0) {
      $this->x = 0;
      }
      elseif($externalX > 20) {
      $this->x = 20;
      }
      else {
      $this->x = $externalX;
      }
   }

   public function getX() {
      return $this->x;
   }
}

$obj = new Test();
$obj->setX('25');
echo $obj->getX();


Asi sem přetaženej tak mi to pomalu myslí. :)
BetaCam
Profil
Mastodont

Takže po noci bez spánku bych chtěl ještě neco upřesnit abych nebyl špatně chápán. Já nezatracuji přístup přes get/set metody viz. můj předchozí post. Používám je den co den. Já se jen asi z čiré nevědomosti nedokážu dovtípit jakou výhodu maj magické metody __get() a __set() oproti například mím výše definovaným getX() a setX() metodám. Nejde mi o get/set metody v globálu, ale o výhodu magických metod __get() a __set(). Je pravda já sem se o magický metody nikdy nějak moc nezajímal, ale když to vemu nějak v letu tak tam žádnou velkou výhodu nevidim.( Pokud nepočítám celkem rychlej zápis při přesetování hodnoty např.: $obj->a++; ) Zato jedna nevýhoda mě hned bije do očí. Je to trochu specifickej příklad, ale to je jedno :

class Test{

	public $x = 'Hodnota X';
	private $props = array('a' => '1', 'b' => 2, 'c' => 3, 'x' => 4);

	public function __construct(){}

	public function __get($externalName){
	    echo '<br />Getting ['.$externalName.'] : ';
        if (isset($this->props[$externalName])) {
            echo 'Value is "'.$this->props[$externalName].'"<br />';
            return $this->props[$externalName];
        } else {
            echo 'This prop doesn\'t exist<br />';
        }
	}
}

$obj = new Test();
echo $obj->x;
$obj->__get('x');
var_dump($obj);
?>


Ve třídě mám public $x s hodnotou "Hodnota X", ale zároveň mám v $props key x s hodnotou "4" no a zde nastává problém. Pokud zavolám echo $obj->x; vypíše se "Hodnota X" abych se dostal do $props budu muset volat $obj->__get('x'); abych dostal hodnotu "4". Takže v podstatě si zavedením magickejch metod zavádim bordel do kódu, protože sice mám "elegantní" set/get přístup přes $obj->a a $obj->a = 10; jenže se na to nedá spolehnout. Zavádí to v kódu akorát nejednotnost přístupu k vlastnostem a to je podle mě akorát bordel. Pokud si udělám "vlastní get metodu" následujícím způsobem :

class Test{

	public $x = 'Hodnota X';
	private $props = array('a' => '1', 'b' => 2, 'c' => 3, 'x' => 4);

	public function __construct(){}

	public function getProperty($externalName){
	    echo '<br />Getting ['.$externalName.'] : ';
        if (isset($this->props[$externalName])) {
            echo 'Value is "'.$this->props[$externalName].'"<br />';
            return $this->props[$externalName];
        } else {
            echo 'This prop doesn\'t exist<br />';
        }
	}
}

$obj = new Test();
echo $obj->x;
$obj->getProperty('x');
var_dump($obj);
?>


mám jistotu jednotného přístupu, protože z venku se do $props budu moct dostat pouze přes metodu getProperty().

Už jenom z tohodle důvodu mi magický metody nějak neseděj. Určitě maj nějaký výhody na který sem nepřišel, protože sem je blíže nestudoval každopádně pokud o nějaké podstatné výhodě víš budu rád, když se semnou o ní podělíš. :)
Mastodont
Profil
BetaCam
jakou výhodu maj magické metody __get() a __set() oproti například mím výše definovaným getX() a setX() metodám

Namísto
$obj->setX(20) 

můžeš volat
$obj->X = 20


A ten poslední řádek může spustit nějaký kód uvnitř třídy. Pokud bude ve třídě deklarace
public $X;

tak řádek $obj->X = 20 nespustí žádný kód, jen se změní hodnota.

Ve třídě mám public $x s hodnotou "Hodnota X", ale zároveň mám v $props key x s hodnotou "4" no a zde nastává problém.

Velkej problém, protože používáš oboje.
Mastodont
Profil
Mmch, existuje i názorová škola, která říká, že public properties jsou e-e a že třídy mají mít veřejné jen metody.
BetaCam
Profil
Mastodont
Mmch, existuje i názorová škola, která říká, že public properties jsou e-e a že třídy mají mít veřejné jen metody.

Do této názorové školy patřím i já a držím se této zásady. Ten příklad byl napsán záměrně takhle, aby ukazoval co může __set a __get dělat za bordel. Mě na tom hlavně vadí to, že jako "uživatele" by mě vůbec neměla zajímat implementace tříd. Pokud, ale někdo navrhne nějaké třídy a bude tam mít něco jako bylo v ukázkovém příkladu může se "uživatel" dostat do situace kdy bude chtít měnit A, ale bude měnit B a to může vést k různejm koncům od vyhození vyjímky až po "nekonečnej" loop. Nakonec se stim bud nejak popere a nebo bude muset otevřít třídu a zjistit proč to v určitejch situacích dělá nesmysli.
Mastodont
Profil
BetaCam
Já proti tomuto směru vcelku nic nenamítám, ale v případě potřeby vlastnosti píšu. A pokud v dokumentaci třídy bude napsáno, že vlastnost A má ten a ten účel a interval jejích povolených hodnot je X-Y, tak jako "uživateli" je mi jedno, jak je to interně implementováno (přičemž očekávám __set). Hlavně aby to fachčilo.
BetaCam
Profil
Mastodont
Hlavně aby to fachčilo
No právě. :)

A pokud v dokumentaci třídy bude napsáno, že vlastnost A má ten a ten účel a interval jejích povolených hodnot je X-Y, tak jako "uživateli" je mi jedno, jak je to interně implementováno (přičemž očekávám __set).

Jistě jenže většina chyb vzniká "chybou" programátora a je jedno jestli neco zapomene ošetřit, něco špatně navrhne, či zapomene odstranit něco co třeba používal pro debug. Chyby vznikaj většinou tam kde nikdo nepočítal, že nastane taková situace, která by způsobovala chybu. A právě __set a __get mi nepřijdou jako metody, které by pomohli takovím situacím předcházet ba právě naopak. :) Zas na druhou stranu si řikám když to tolik lidí používá tak na tom asi něco bude. :) No třeba jim za nějakej čas taky přijdu na chuť. :)

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: