Autor Zpráva
midlan
Profil
Ahoj,
mám dotaz k dědičnosti. Mám abstraktní třídu, od které dědí další 2 třídy (řekněme A a B). Třída A dědí konstruktor beze změny, ale u třídy B bych potřeboval do konstruktoru přidat jeden parametr. Myslím, že podle pravidel OOP musí zůstat parametry kompatibilní s rodičem, jen se může přidat nějaký nakonec. Jenže to se mi nehodí, protože asi posledních 5 parametrů na konci konstruktoru rodičovské abstraktní třídy jsou parametry s předem vyplněnou hodnotou a v praxi se budou vyplňovat jen vyjímečně. Pokud budu tedy chtít vytvořit instanci třídy B, budu muset vyplňovat všechny parametry, které s největší pravděpodobností jen opíšu, jen kvůli tomu, že jako poslední parametr potřebuji předat instanci. Jde to vyřešit nějak jinak?
noName
Profil *
Můžeš využít setter. Uděláš si metodu

setNeco($neco) { 
$this->neco = $neco; 
return $this;
}
juriad
Profil
Konstruktory potomků mohou vypadat jakkoli. Prefixem nemusí být parametry konstruktoru předka.
Jediné, co musíš zajistit, je zavolání kontruktoru předka.

class Abst {
function  __construct($x, $y, $z) {
  echo $x, $y, $z;
}
}

class A extends Abst {
function  __construct($a, $z, $b, $x) {
  parent::__construct( $x, 'y', $z);
  echo $a, $b;
}
}

$a = new A('a', 'z', 'b', 'x');

Klasické dědění metod se netýká konstruktorů, tam platí odlišná pravidla.

Note: Parent constructors are not called implicitly if the child class defines a constructor. In order to run a parent constructor, a call to parent::__construct() within the child constructor is required. If the child does not define a constructor then it may be inherited from the parent class just like a normal class method (if it was not declared as private).
Joker
Profil
midlan:
Říká se tomu přetěžování metod a PHP to, pokud vím, nepodporuje.
edit:
ad juriad [#3], je pravda, že s konstruktorem to jde.


V PHP to jde udělat přes nepovinný parametr v metodě rodičovské třídy. Jestli ten jeden parametr je potřeba jen na nějakou izolovanou operaci, šlo by ještě udělat separátní metodu, která by tu operaci udělala zvlášť.

asi posledních 5 parametrů na konci konstruktoru
Kolik jich probůh ten konstruktor má?
Obvykle se nedoporučuje dávat metodám příliš mnoho parametrů (jsou případy, kdy je to nutné, ale často je to prostě jen chyba)
midlan
Profil
juriad:
Parent constructors are not called implicitly if the child class defines a constructor. In order to run a parent constructor, a call to parent::__construct() within the child constructor is required.
Ony se snad volají rodičovské metody automaticky, když je v potomkovi přepíšu? Pokaždé musím volat parent::[metoda]() ať už se jedná o metodu kontruktoru nebo normální metodu, nebo ne?

Joker:
Jestli ten jeden parametr je potřeba jen na nějakou izolovanou operaci, šlo by ještě udělat separátní metodu, která by tu operaci udělala zvlášť.
Ne není to je jedna operace, třída s tou instancí bude pracovat neustále.

Takže řešením je prostě přeházet si parametry konstruktoru podle potřeby?
juriad
Profil
midlan:
Chtěl jem tím říct, že u metod musíš zajistit identické rozhraní (počet a pořadí parametrů), kdežto u konstruktoru to nutné není. Konstruktor vždy voláš nad konkrétní třídou, tedy víš, jak ten konstruktor vypadá. Pokud je navíc předkem abstraktní třída, tak ta sice konstruktor mít může, ale nikdy jej uživatel nemůže zavolat a tedy znalost jeho rozhraní je pro uživatele neužitečná.
Přikláním se k názoru, že rozhraní konstruktorů můžeš volně ale střídmě změnit při dědění. Ale přijde mi rozumné zachovat pořadí parametrů, které zůstaly. Parametr jednoho typu můžeš nahradit (na jeho místě) jedním či více (nenapadá mě přiklad) parametry, pokud je zřejmé, že souvisí/nahrazují původní parametr. A možná bych ještě připustil přesunutí některých parametrů na začátek seznamu.
To ale jen za předpokladu, že se jedná o často používané rozhraní, u kterého je k tomu dobrý důvod. Pokud budeš mít hierarchii tříd, které se v celé aplikaci zinstanciují jedinkrát, spíš bych byl konzervativní.

Ukážu příklad, který mi přijde rozumný (nehodnotit, zda má takovou hierarchii vůbec smysl budovat a zda právě takto):

class FormElem {
  funmction __construct(string $tagName, string $name, array $values) {}
}

class Select extends FormElem {
  function __construct(string $name, array $optionsWithValues, bool $multi) {
    parent::__construct('select', $name, $optionsWithValues);
  }
}

class TextBox extends FormElem {
  function __construct(string $name, string $placeholder) {
    parent::__construct('input', $name, array(''));
  }
}
midlan
Profil
a co říkáš na něco takového:

<?php

abstract class Auto {
  function __construct($nazev, array $vybava = array('klimatizace', 'ABS', 'mlhovky', 'rádio'), $pojizdne = true, $pojistene = false);
}

class OsobniAuto extends Auto {
  function __construct($nazev, Ridic $ridic, array $vybava = array('klimatizace', 'ABS', 'mlhovky', 'rádio'), $pojizdne = true, $pojistene = false);
}

class SamoridiciAuto {
#auto se řídí samo, takže nepotřebuje instanci řidiče, konstruktor dědí nepozměněný
}
midlan
Profil
Zhodnotí prosím někdo jestli je mnou uvedený příklad dá považovat za správný?
juriad
Profil
midlan:
Mě to přijde v pohodě. Jelikož chceš mít povinný parametr $ridic, nezbyde ti nic jiného než ho umístit před ty nepovinné. Ano, mohl bys mu dát výchozí hodnotu NULL a sledovat, zda hodnota se od NULL liší.
Nicméně, osobního auto je možné zaparkovat a řidič může vystoupit. Nepřijde mi to proto jako úplně povinný parametr a možná bych šel cestou setteru.

Ale klidně to tak měj; poznáš sám během času, zda to byla štastná volba. Refactoring by zas tak složitý nejspíš nebyl.
Kajman
Profil
midlan:
dá považovat za správný?

Nemá SamoridiciAuto dědit z Auto?
midlan
Profil
juriad:
Dobře, udělám to tak jak jsem uvedl v příkladu. Tohle není přesný příklad (je to snad dostatečně poznat), ale uvedl jsem stejný počet a typ paramterů, v praxi se bude instance předaná v konstruktoru používat pořád.

Kajman:
Nemá SamoridiciAuto dědit z Auto?
Ano má, moje chyba.

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