Autor Zpráva
4ever
Profil
Ahoj,
mám dotaz ohledně použití slova global uvnitř metody.

Mám tři soubory:
index.php, basic_class.php a form_class.php

V basic_class.php mám nadefinovanou vlastnost:
var $degree;


V form_class.php mám metodu
public function mojemetoda(){
$basic->degree="hodnota"}


V index.php nejdříve načtu instanci objektu $basic a poté $form.
Pak v index.php volám metodu $form->mojemetoda(); a jelikož jsem uvnitř mojemetoda nedeklaroval instanci $basic jako globalní proměnnou, tak ji nemohu zpřístupnit uvnitř index.php.

Proto se teď ptám jak se to dělá v OOP praxi? Je třeba do každé metody třídy form_class nadeklarovat globální proměnnou - všechny instance tříd/objektů, které chci, aby byly přístupné? Nebo existuje nějaká finta jak to v OOP zjednodušit?
Majkl578
Profil
Zaprvé, než budeš pokračovat, prohlub si znalosti OOP v PHP 5, var se používalo v PHP 4 a v PHP 5 nemá co dělat.
Zřejmě pak dojdeš k tomu, že to nahradíš za public $degree;, na to ale taky hned zapomeň, protože by to porušovalo zapouzdření objektu.
Výsledkem bude použít private $degree; a k získání té hodnoty zvenčí se použije tzv. getter (metoda getDegree vracející hodnotu a setter hodnotu nastavující. Např. tedy:
class Foo
{
    private $degree;
    
    /** getter */
    public function getDegree()
    {
        return $this->degree;
    }
    
    /** setter, ošetřuje vstup a vrací instanci sebe sama (umožní řetězení volání) */
    public function setDegree($degree)
    {
        $this->degree = (float) $degree;
        return $this;
    }
}

V praxi se global uvnitř metod nepoužívá nikdy.
Pro předání instance jiné třídy se používá buď předání parametrem, nastavením pro celou třídu nebo se využívá pokročilejších přístupů jako např. Dependency Injection (odkaz na Nette dokumentaci je úmyslný, uvidíš to tam i na konkrétním příkladu) bebo Service locator.
4ever
Profil
No dík za vysvětlenou, ale protože Nette nepoužívám je mi to dost cizí, takže z toho DI moc nerozumím. Nejde to vysvětlit nějak jednodušeji bez frameworku (a česky)?

Stejně nechápu jak že ten objekt není zapouzdřený když použiju public.

Představ si tento příklad z index.php:
$form->unknown_time = ($form->unknown_time=="on")?1:0;

a s getterem:
$form->get('unknown_time') = ($form->get('unknown_time')=="on")?1:0;


Nezačíná se to pak nějak moc komplikovat? Mě se zdá jednoduší prostě použít public a víc neřešit.
Alphard
Profil
4ever:
Na DI asi zatím zapomeňte, podstata je velmi jednoduchá, jestliže ale začínáte s OOP, dejte tomu čas.

Pokud jde o public vlastnosti, občas se vyskytnou, Majkl to bere velmi dogmaticky (právě jsem vyprovokoval flame :-)). Více o této válce v diskusi u http://php.vrana.cz/prace-s-vlastnostmi-pomoci-metod.php. Je tam zmíněné i magické get/set, v Nette děděné od Nette\Object.

Váš příklad, i když by to tak (možná) šlo sestrojit, není typický, ty metody by nebraly jméno proměnné jako parametr, ale byly by vytvořené pro každou z nich
$form->setDegree($form->getDegree=="on"?1:0);
Výhoda je v tom, že v metodě setDegree může být např. validace, která zabrání nastavení chybné hodnoty a uvedení instance do invalidního stavu.
Majkl578
Profil
4ever:
Stejně nechápu jak že ten objekt není zapouzdřený když použiju public.
Protože můžeš zvenčí změnit hodnotu té vlastnosti a změnit tak vnitřní stav objektu, který by se tak mohl stát nekonzistentním.

$form->get('unknown_time')
Toto není getter vlastnosti, ale jen nějaká magická metoda dělající cosi. Getter/setter se jmenuje podle vlastnosti, tak jak jsem uvedl.

($form->get('unknown_time')=="on")?1:0
Toto má být co? Používáš 1 a 0 pro logické hodnoty? To snad ne...
Nevypadá toto lépe?
$isOn = $form->getUnknownTime() === 'on'; 

O Dependency Injection je seriál na Zdrojáku, ale jak říká Alphard, na to máš čas, zmínil jsem ho jen jako pokročilé řešení problému.

Nezačíná se to pak nějak moc komplikovat?
Spíš naopak. Můj kód je jednodušší a přehlednější než tvůj.

Mě se zdá jednoduší prostě použít public a víc neřešit.
Tak to máš špatné zdání. Výše jsem uvedl proč.
4ever
Profil
Alphard:
Díky. Ulevilo se velmi :-)

Ještě tu ale zůstává problém... Jedná se mi o to jak zpřístupnit instanci třídy v jiné třídě. Je tu ta možnost udělat to pomocí argumentu to funkce a tak toto je můj kód:

class Form_class {
  private $errors = array();
  public $name;
  public $day;
  public $month;
  public $year;
  public $hour;
  public $minute;
  public $unknown_time;
  public $timezone;
  public $long_deg;
  public $long_min;
  public $ew;
  public $lat_deg;
  public $lat_min;
  public $ns;

	function __construct($arr) {
	 // nejdříve, při zavedení instance objektu, kontroluje povinné údaje
	 $this->checkStrings($arr, true);
	 $this->convertGeoPositions($basic); // PŘEVOD GEOPOLOHY NA STUPNĚ př. -48°45' -->   }

	public function convertGeoPositions($basic) {
  // PŘEVOD NA STUPNĚ př. -48°45' --> -48.75°
echo $basic->longitude_degree;  
  $basic->longitude_degree = $this->ew * ($this->long_deg + ($this->long_min / 60));
  $basic->latitude_degree = $this->ns * ($this->lat_deg + ($this->lat_min / 60));
  
  }
}


Takže abych mohl pracovat s proměnnými ostatních tříd, musel bych do konstruktoru vložit $pole_s_instancema nebo jenom jedno instanci $basic.

__construct($arr,$pole_s_instancema)



Co to má dělat: Po zadání dat do formuláře, se to odešle a zpracovává pomocí třídy form_class. Během iniciace třídy se v konstruktoru ověří data a převedou se geologické údaje na formát pro matematický výpočet a tento se má uložit do instance basic. Proto aby se to číslo mohlo uložit, musím basic zpřístupnit uvnitř třídy form_class.
Alphard
Profil
4ever:
abych mohl pracovat s proměnnými ostatních tříd, musel bych do konstruktoru vložit $pole_s_instancem
Tahle myšlenka se blíží DI. Předání kontejneru obsahujícího instance tříd (souvisí s použitím továrniček, viz odkázané články).

Konkrétně těžko radit, z toho úseku kódu a popisu nevím, co to má dělat.
Ale jestli form má být formulář, tak by asi neměl obsahovat metodu convertGeoPositions(). Třídu si do jisté míry představte jako rozšířenou funkci, která by měla dělat jen jednu věc (ale dobře). Opět, když bych šel ještě dál, tak někteří říkají, že třída má obsahovat buď v zásadě data, nebo především metody (pro práci s datovými třídami). Např třída Message obsahující mailovou zprávu by se pak nemohla sama odeslat, ale potřebovala by Mailer. A opět bych mohl odkázat na článek stejného autora s hodně dlouhou diskusí, kde se například řešilo, jestli se může obrázek sám zmenšit. Jestli tohle uvidí Majkl, asi to s ním sekne a zase se tady delší dobu neukáže :-)
4ever
Profil
Majkl578:
Problém je v tom, že těch vlastností tam je více (viz můj poslední příspěvek a ukázka kódu). Takže bych musel udělat min. 14 setterů a 14 getterů.... do třídy Form_class. Ještě tam je ta druhá třída.
4ever
Profil
Alphard:
Form_class zpracovává data z formuláře včetně ověření korektnosti, formátu a převodu; a instance drží ty informace z formuláře.

To Basic_class má hlavně provádět matematické výpočty.
Alphard
Profil
Form by se měla starat pouze o validaci přijatých dat. Pokud jsou v pořádku, jsou předány nadřazenému objektu a Form ztrácí řízení. Ona svou práci udělala, matematické výpočty nejsou její zodpovědnoust a neměly by být prováděny jejím prostřednictvím. Data tedy přebírá controller $form->getValues() a předá je k dalšímu zpracování.
V jakém formátu jsou data předány není až tak podstatné, v nejjednodušším případě to může být pole, ve složitějším třeba referencí na instanci obsahující data. Jen je rozumné použít nějaký kontejner, abyste nevypisoval 20 proměnných.
Majkl578
Profil
4ever:
Takže bych musel udělat min. 14 setterů a 14 getterů.
Což je samozřejmě naprosto správně.
4ever
Profil
Majkl578, Alphard:
Díval jsem se na to DI. Prvnímu dílu rozumím. Druhý díl už je pro mě hůře srozumitelný kvůli zkráceným kódům; předpokládám, že je nutné doplnit definici interface. Nejlepší by tedy bylo udělat nejprve globální či nadřazený objekt pro obě třídy. Vytvořit instanci globálního objektu, poté dovnitř vytvořit instanci basic a instanci form. Měl by tam být controller, který teď představuje index.php, jenže index.php je kapánek dlouhý a složitý, takže do tak složitého úkonu bych se zatím nerad pouštěl. I když princip asi chápu, stejně bych nevěděl jak to udělat, pokud by někde nebyl krok za krokem návod.

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:

0