Toon posts:

[PHP5] OO: rare volgorde uitvoeren inheritance oid?

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik kon er even geen betere titel voor verzinnen.

Mijn doelstelling is de volgende. Een class heeft als private veld een array. Ik wil de count van deze array kunnen opvragen via een public var, zonder haakjes te hoeven gebruiken.

Dus niet:
PHP:
1
  echo $myobj->get_arr_count();

maar:
PHP:
1
  echo $myobj->arr_count;

Stel ik heb de volgende basisclass:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// base class from which all classes will inherit. Handles the array of public members and their getters and setters.
class base_class {
  // protected
  protected $arr_values; // will contain array of public accessible members
  // getter
  public function __get( $key ) {
    echo "getting value for " . $key . "\n";
    if ( array_key_exists( $key, $this->arr_values ) ) {
      echo "returning value:" . $this->arr_values[$key]. "\n";
      return $this->arr_values[$key];
    }
    die( "Can't access that property!\n" . $key . "\n" );   
  }
  // setter
  public function __set( $key, $value ) {
    echo "setting " . $key ." to " . $value . "\n";
    if( array_key_exists( $key, $this->arr_values ) ) {
      $this->arr_values[$key] = $value;
    } else {
      die( "You can't set that property!\n" );
    }
  }
  // constructor
  public function __construct() {
    $this->arr_values = array("classname"=>"base_class");
  }
  // destructor
  public function __destruct() { 
    unset($this->arr_values);  }
}


Nu ga ik daar een afgeleide van maken:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class list_class extends base_class {
  private $arr_list;
  public function __construct() {
    // call constructor (inherited)
    parent::__construct();
    $this->classname = "list_class";
    $this->arr_values = array_merge($this->arr_values, array(
      "list_count"=>0
    ));
  }
  public function __get( $key ) {
    if ($key=="list_count") {       
      $this->list_count = is_array($this->arr_list)?count($this->arr_list):0;
    }
    parent::__get( $key );
  }
  public function __destruct() {
    // call destructor (inherited)
    parent::__destruct();
  }
  public function add_item($item) {
    $this->arr_list[]=$item;
  }
}


Als ik dit nu aanroep met deze code:

PHP:
1
2
3
$obj_test = new list_class; 
$obj_test->add_item("blaat"); 
echo "got value:" . $obj_test->list_count . "\n";


Dan krijg ik dit als resultaat:
setting classname to list_class
setting list_count to 1
getting value for list_count
returning value:1
got value:
Heel raar dus. De getter retourneert wel netjes 1, maar in mijn applicatie krijg ik een lege var terug?

Iemand enig idee waarom?

[ Voor 23% gewijzigd door Verwijderd op 01-10-2005 16:16 ]


Verwijderd

moet __get() niet een waarde terug geven? in je base_class geeft-ie wel een waarde terug, maar als die functie wordt aangeroepen door de extended class gaat de teruggegeven waarde verloren.

ergo,
PHP:
1
2
3
4
5
6
public function __get( $key ) { 
    if ($key=="list_count") {        
      $this->list_count = is_array($this->arr_list)?count($this->arr_list):0; 
    } 
    return parent::__get( $key ); 
  }

Verwijderd

Topicstarter
Dat was inderdaad de hele truuk :P

Toch vind ik dit een raar fenomeen. Ik ben van oorsprong Pascal (Delphi) programmeur, en daar bestaat het keyword 'inherited', wat in feite zoveel betekend als 'ga nu de flow van de basisclass uitvoeren'. In de basisclass staat al een return, die zou dus gewoon de waarde moeten retourneren.

Nu lijkt het alsof je 2 objecten hebt, de basis class en de afgeleide, en dat de afgeleide een functie aanroept van de afgeleide.

Of ben ik de enige die dit raar vind?

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Dat is dan toch juist niet raar? Na de 'inherited' returned hij naar de afgeleide klasse en dus moet je de door de basisklasse teruggegeven waarde nogmaals returnen om de waarde uit de afgeleide functie aan het progamma terug te geven?

edit:
Ohnee, wacht, met Delphi is het zo dat met 'inherited' de code als het ware 'ingevoegd' wordt, in plaats van aangeroepen. Dan is het inderdaad niet nodig nog een return te geven.

[ Voor 30% gewijzigd door Confusion op 01-10-2005 16:36 ]

Wie trösten wir uns, die Mörder aller Mörder?


  • Michali
  • Registratie: Juli 2002
  • Laatst online: 22-03 18:12
Het lijkt niet alleen zo, het is ook zo. Ik vind het wel logisch. Je overschrijft een functie in princiepe, maar je kunt er dan toch nog gebruik van maken via parent::functie() ipv. $this->functie().

Je hoeft __destruct ook niet te te defineren je in subclass dacht ik. Die wordt gewoon inherit.

Noushka's Magnificent Dream | Unity


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 15-04 22:07

NMe

Quia Ego Sic Dico.

Michali schreef op zaterdag 01 oktober 2005 @ 16:32:
Het lijkt niet alleen zo, het is ook zo. Ik vind het wel logisch. Je overschrijft een functie in princiepe, maar je kunt er dan toch nog gebruik van maken via parent::functie() ipv. $this->functie().
Het hele idee van inherited in Delphi/Object Pascal is dat je niets hoeft returnen. Je hoeft slechts "inherited" ergens in je method te zetten, en dan wordt daar in principe de code van je basismethod ingevuld. Wat die returnt, returnt ie dus aan het aanroepende stuk code, en niet eerst nog eens aan de afgeleide method. :)

Persoonlijk vind ik de Delphi-manier ook fijner werken eigenlijk. :)

[ Voor 6% gewijzigd door NMe op 01-10-2005 16:37 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Verwijderd

mwoah... dit is opzich wel logisch... je zit in een functie en roept een andere functie aan... het zou dan raar zijn als die andere functie de return value voor je hoofdfunctie bepaalt zonder dat je dat aangeeft

  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
-NMe- schreef op zaterdag 01 oktober 2005 @ 16:36:
[...]

Persoonlijk vind ik de Delphi-manier ook fijner werken eigenlijk. :)
Het beperkt meer. Hoe wil je immers nog het resultaat van een parent functie gaan gebruiken op zo'n manier. En hoe gebeurt het als de parentclass (parent)private variabelen aanroept en deze code wordt 'ingeplakt' binnen de functie van de derived class?

Verwijderd

Topicstarter
Verwijderd schreef op zaterdag 01 oktober 2005 @ 16:42:
mwoah... dit is opzich wel logisch... je zit in een functie en roept een andere functie aan... het zou dan raar zijn als die andere functie de return value voor je hoofdfunctie bepaalt zonder dat je dat aangeeft
Nee, je roept helemaal geen andere functie aan.

Iemand die dat zegt, heeft imo OO niet begrepen ;)

Het enige wat je doet, is aangeven waar de inherited code uitgevoerd moet worden. Maar je bevind je nog steeds in dezelfde functie.

Er is maar 1 object met 1 functie. Die functie wordt opgebouwd uit eigen code, en code van de ancestor. Daarom vind ik het raar dat dit zo moet :)
Het beperkt meer. Hoe wil je immers nog het resultaat van een parent functie gaan gebruiken op zo'n manier.
Er is geen parent functie. Er is een ancestor functie. En die zit al in het object zelf.


Kijk, ik zie het zo.. als ik classes heb

code:
1
2
3
4
5
class deze_class
  property iets

class die_class extends deze class
  property nogiets


ik instantieer nu een object van 'die_class'. Wat ik dan in feite krijg is dit:

code:
1
2
3
object van class die_class
  property iets
  property nogiets


terwijl de manier waarop PHP het doet, suggereert dat je dit krijgt:

code:
1
2
3
4
object van class die_class
  property object van class deze_class
  ->property iets
  propertie nogiets


De functie __get, is gewoon de functie __get. In de inherited code staat al een return. Ik vind het dan raar dat je dat nog een keer moet doen. Return betekent immers "beeindig deze functie en ga terug naar aanroepende code met waarde <waarde>".

edit:
wat betreft die destructor; die hoefde ik inderdaad niet te herhalen in de afgeleide class. Dat heb ik wel gedaan, omdat in de 'echte' code nog wel zaken zitten die in de destructor vrijgegeven moeten worden. M'n garbage collect ik zelf wel, thank you :)

[ Voor 55% gewijzigd door Verwijderd op 01-10-2005 17:42 ]


  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
Verwijderd schreef op zaterdag 01 oktober 2005 @ 17:35:
Er is geen parent functie. Er is een ancestor functie. En die zit al in het object zelf.


Kijk, ik zie het zo.. als ik classes heb

code:
1
2
3
4
5
class deze_class
  property iets

class die_class extends deze class
  property nogiets


ik instantieer nu een object van 'die_class'. Wat ik dan in feite krijg is dit:

code:
1
2
3
object van class die_class
  property iets
  property nogiets


terwijl de manier waarop PHP het doet, suggereert dat je dit krijgt:

code:
1
2
3
4
object van class die_class
  property object van class deze_class
  ->property iets
  propertie nogiets


De functie __get, is gewoon de functie __get. In de inherited code staat al een return. Ik vind het dan raar dat je dat nog een keer moet doen. Return betekent immers "beeindig deze functie en ga terug naar aanroepende code met waarde <waarde>".
Jouw zienswijze staat haaks op encapsulation. Je zou een class moeten kunnen uitbreiden zonder dat jij de implementatie van de desbetreffende class kent en slechts met de gegeven methodes. Echter met jouw idee van uitbreiding komt alle implementatie binnen van de base class en kunnen we dus ook zonder problemen private variabelen wijzigen van de base class (of zie je een manier om daarop onderscheid te maken?)

Verwijderd

Topicstarter
Glimi schreef op zaterdag 01 oktober 2005 @ 17:47:
[...]

Jouw zienswijze staat haaks op encapsulation. Je zou een class moeten kunnen uitbreiden zonder dat jij de implementatie van de desbetreffende class kent en slechts met de gegeven methodes. Echter met jouw idee van uitbreiding komt alle implementatie binnen van de base class en kunnen we dus ook zonder problemen private variabelen wijzigen van de base class (of zie je een manier om daarop onderscheid te maken?)
Mijn zienswijze staat niet haak op encapsulation. Private variabelen zijn wel private. Voor variabelen die je ook in afgeleide classes wilt kunnen gebruiken, heb je het protected keyword. Dat onderscheid wordt dus gemaakt door iets private of protected te maken.

Encapsulation slaat imo meer op 'het object' (dus de geinstantieerde class) t.o.v. de buitenwereld. Niet op 'ancestor' en 'class'.

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ik zie ook niet precies hoe jouw manier van denken werkt maar even een voorbeeldje waarom ik het logisch vindt dat je nog een keer moet returnen

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Employee
{
    private float _salary;
    public virtual float GetSalary()
    { return _salary; }
}

public class GreedyManager : Employee
{
    public override float GetSalary()
    {
        float salary = base.GetSalary();
        return salary * 4;
    }
}

als de return hier automatisch gedaan zou worden kan je toch niks meer wijzigen aan een reeds bestaande functie. Het idee bij OO is juist dat je de implementatie kan veranderen in een child class.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Verwijderd

Topicstarter
Dit kan precies op de manier die ik in mijn TS aangeef. Door aan te geven waar de inherited code aangeroepen moet worden.

  • GX
  • Registratie: Augustus 2000
  • Laatst online: 14-05-2025

GX

Nee.

Verwijderd schreef op zaterdag 01 oktober 2005 @ 17:35:
Nee, je roept helemaal geen andere functie aan.
Jawel, want:
Iemand die dat zegt, heeft imo OO niet begrepen ;)
En PHP ook niet. Je kan er niet van uit gaan dat OO principes in elke taal hetzelfde werken, vóóral in PHP niet, welk met zijn OO-ondersteuning nog maar in de kinderschoenen staat.

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Verwijderd schreef op zaterdag 01 oktober 2005 @ 18:48:
Dit kan precies op de manier die ik in mijn TS aangeef. Door aan te geven waar de inherited code aangeroepen moet worden.
Ik zie dan niet hoe je nog wijzigingen kunt aan brengen in het resultaat van de functie?

Wat jij in jouw get functie doet is een property setten en dan gewoon het resultaat uit de base class doorgeven. In het geval van simpele propertys werkt dat wel maar als je echt nog wijzigingen wilt maken aan de hand van wat er uit komt dan zul je toch echt zelf moeten returnen lijkt mij. Anders snap ik niet wat jij bedoelt.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Verwijderd

Topicstarter
Tsja, ik zou bijna zeggen, verdiep je eens in het OO model van Delphi.. die werkt namelijk prima, en wel op de manier waarop ik beschrijf :)

Overigens zijn andere op- en aanmerkingen op de code uit de TS meer dan welkom. De code uit de TS is tot stand gekomen door mijn kennis van OO in Delphi, en veel inleeswerk in PHP.. ik weet dus niet of ik e.e.a. uberhaupt wel op de juiste manier aanpak.

Voorbeeld:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Employee { 
  private float _salary; 
  public virtual float GetSalary() { 
    return _salary; 
  } 
  public virtual float SetSalary(salary) {
    _salary=salary;
  }
} 

public class GreedyManager : Employee { 
  public override float GetSalary() { 
     base.SetSalary(base.GetSalary*4); 
     inherited;
  }
} 


Sowieso vind ik jouw code niet netjes. Je hebt dan een private var, die _salary heet, waar NIET het salaris instaat, maar slechts 1/4 van het salaris. In mijn voorbeeld staat in die private var WEL het salaris.

Let overigens niet teveel op de code. C# is not my cup of tea. Natuurlijk zou de code zoals ik 'm nu neerzet, in 'het echie' niet zo werken, immers dan zou het salaris bij elke get met 4 vermenigvuldigd worden :P

[ Voor 55% gewijzigd door Verwijderd op 01-10-2005 19:07 ]


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Verwijderd schreef op zaterdag 01 oktober 2005 @ 19:02:
Sowieso vind ik jouw code niet netjes. Je hebt dan een private var, die _salary heet, waar NIET het salaris instaat, maar slechts 1/4 van het salaris. In mijn voorbeeld staat in die private var WEL het salaris.
Daarom had ik de class ook GreedyManager genoemd ;). Mischien had ik als voorbeeld beter PaySalary kunnen nemen ( Dus dat er elke maand 4 keer zijn salaris betaald wordt ( vandaar de "Greedy" ) ). In de code is het dus ook niet de bedoeling dat het salaris veranderd wordt.

Ik had al verwacht dat jij dit zo zou doen en ik kan me ook wel indenken hoe je er mee moet werken maar het legt wel een aantal beperkingen op. Zo kun je dus de uitkomst van jou methode niet laten afhangen van je "inherited" code. Je kan alleen eventueel wat extra code van te voren draaien zodat de waarde veranderd.

Jou voorbeeldje zou bijvoorbeeld ook niet opgaan als er geen SetSalary methode is.
Let overigens niet teveel op de code. C# is not my cup of tea.
daarom zet ik het ook niet in php aangezien ik daar niet zoveel van weet maar de syntax is niet al te verschillend dus wel begrijpenlijk lijkt me

[ Voor 21% gewijzigd door Woy op 01-10-2005 19:22 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • joepP
  • Registratie: Juni 1999
  • Niet online
Verwijderd schreef op zaterdag 01 oktober 2005 @ 16:27:
Dat was inderdaad de hele truuk :P

Toch vind ik dit een raar fenomeen. Ik ben van oorsprong Pascal (Delphi) programmeur, en daar bestaat het keyword 'inherited', wat in feite zoveel betekend als 'ga nu de flow van de basisclass uitvoeren'. In de basisclass staat al een return, die zou dus gewoon de waarde moeten retourneren.

Nu lijkt het alsof je 2 objecten hebt, de basis class en de afgeleide, en dat de afgeleide een functie aanroept van de afgeleide.

Of ben ik de enige die dit raar vind?
Ik ben van origine ook Delphi programmeur, maar ik denk toch echt dat je ergens een denkfout maakt. In Delphi is inherited "gewoon" een functieaanroep, en als je dus iets aan Result toekent in de baseclass wordt dat niet automatisch doorgegeven.

Voorbeeldje:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
type
  TBaseClass = class
  public
    function Get: String; virtual;
  end;

  TNewClass = class(TBaseClass)
  public
    function Get: String; override;
  end;

implementation

function TBaseClass.Get: String;
begin
  Result := 'BaseClass';
end;

function TNewClass.Get: String;
begin
  inherited Get;
end;


TNewClass.Create.Get geeft gewoon een lege string terug. Wil je de inherited informatie teruggeven dan moet je Result := inherited Get; gebruiken.
Pagina: 1