[PHP] Class type-casting

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Myrdhin
  • Registratie: April 2000
  • Laatst online: 16:53
Eerst even wat uitleg:
Ik heb een aantal tabellen in de database staan: item, nieuws, artikel.

Item bevat de data die voor alle informatie nodig is zoals poster, datum publicatie etc. Er staat ook een type en een verwijzings id in. Afhankelijk van het type zoek ik in de juiste tabel (nieuws of artikel) het verwijzings id op. Een artikel table bevat bijvoorbeeld extra informatie over het artikel zoals aantal pagina's etc. Ik heb hiervoor gekozen omdat ik dan niet steeds dezelfde informatie in tabellen aan het zetten ben.

In PHP heb ik een hoofdklasse "item". En 2 afgeleide klassen "nieuws" en "artikel".

Nu loop ik tegen het volgende probleem op: In eerste instantie weet ik nog niet of een item id een artikel of nieuwsitem is. Ik gebruik dus de klasse "item". Pas nadat ik gekeken heb welk type het is wil ik eigenlijk een soort van "type-cast" doen naar de goede klasse (nieuws of artikel). Dit werkt niet (en is ook nog eens niet zo'n goede programmeermethode....)

Als oplossing had ik het volgende in gedachte:
1. Naast klasse item een nieuwe klasse nieuws en artikel maken die niet gebouwd zijn op de klasse item. Bij het aanroepen van de constructor van klasse nieuws of artikel kan ik een pointer doorgeven van de item klasse en zo ook bij de basis elementen komen.

2. Wel een nieuws en artikel klasse maken gebaseerd op klasse item en gewoon als het type vastgesteld is een "new" aanroepen van de juiste klasse, dus eigenlijk de basis gegevens 2x uit de database halen.

Ik heb nu oplossing 2 gemaakt en dat werkt wel, maar dus wel met een overhead. Oplossing 1 lijkt me mooier en tevens sneller. Misschien heeft iemand hier nog een ander idee?

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je moet op het moment van instantieren dus ook het type weten. Je kunt dus geen Item instantieren, het is namelijk niet alleen een Item, maar meer dan een Item. Het casten na de instantieren lukt logischerwijs ook niet, het is immers geen NieuwsItem of een Artikel

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Myrdhin
  • Registratie: April 2000
  • Laatst online: 16:53
Dus in dit geval heb je last van het kip en ei probleem. Om het type te weten moet je eerst instantieren, maar dat kan niet omdat je niet weet welk type je moet instantieren..

Dan zit je dus toch vast aan een van de oplossingen die ik aangaf. Mijn voorkeur gaat dan eigenlijk uit naar de eerste vanwege de lage overhead, maar is dat de juiste OO aanpak? Of is er misschien nog een 3e (of misschien wel 4e) mogelijkheid?

[ Voor 5% gewijzigd door Myrdhin op 29-09-2003 19:56 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Om het type te weten moet je eerst instantieren, maar dat kan niet omdat je niet weet welk type je moet instantieren..
Je leest toch eerst de data uit de database voordat je gaat instantieren? En als je die data weet weet je wat je moet instantieren.
Waarvoor moet je het dan 2x uit de database halen?

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Myrdhin
  • Registratie: April 2000
  • Laatst online: 16:53
In die klasse worden nu juist alle database spullen afgehandeld. Ik heb een klasse Db. De klasse item haalt via Db::getInstance de db connectie op en doet daarna al het query werk. Oftewel de klasse is al het ware een laag tussen mijn programma en de database. Juist om die reden heb ik dat in een klasse geprogrammeerd.

Acties:
  • 0 Henk 'm!

  • mulder
  • Registratie: Augustus 2001
  • Laatst online: 16:24

mulder

ik spuug op het trottoir

hoe kan het dan dat je op dat moment niet weet wat voor type het is?

oogjes open, snaveltjes dicht


Acties:
  • 0 Henk 'm!

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06 13:31

drm

f0pc0dert

Ik begrijp er niets van.

Waarom heb je een extra stap nodig tussen wat jij noemt 'instantieren' en 'casten' :? Wat gebeurt er tussen die 2 stappen wat niet voor het instantieren kan gebeuren :?

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


Acties:
  • 0 Henk 'm!

  • Myrdhin
  • Registratie: April 2000
  • Laatst online: 16:53
Ik zal het proberen uit te leggen met een stukje code:

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
31
<?php
class Item {
  var $db;
  var $id;
  // Nog meer variabelen die voor een item nodig zijn

  function Item($id = 0) {
    $this->db = Database::getInstance();   // Pak een database instance
    if ($id <> 0)
      $this->getItem(intval($id));
  }


  function getContent($id) {
    $sql = "select bladiebla from item tabel";
    $array = $this->db->fetchArray($this->db->query($sql));
    $this->makeItem($array);   // Vul de klasse variabelen (functie niet uitgeschreven)
  }

  function getId() {
    return $this->id;
  }

  function getType() {
    return $this->itemtype;
  }

  function getItemSubId()
    return $this->itemsubid;  // wordt gebruikt als id in de nieuws of artikel tabel
}
?>


Nu de klasse nieuws:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class Nieuws extends Item {
  function Nieuws($id = 0) {
    $this->Item($id);
    $this->getNieuws($this->getItemSubId());
  }

  function getNieuws($id) {
    $this->getItem($id);
    $sql = "mooi select statement voor de nieuws tabel";
    $array = $this->db->fetchArray($this->db->query($sql));
    $this->makeNews($array);  // Vul de klasse variabelen (functie niet uitgeschreven
  }
}
?>


Nu het hoofdprogramma:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$id = $_GET['id'];

$item = new Item($id);
switch ($item->getType) {
case 'Nieuws':
    $nieuws = new Nieuws($id);
    // Output nieuws item etc.
   break;
case 'Artikel':
    $artikel = new Artikel($id);
    // Output artikel item etc.
    break;
}
?>


Zoals je ziet weet ik pas het type als ik eerst het item ophaal via de klasse item. Daarna moet ik datzelfde item opnieuw instantieren met het juiste klasse type voor nieuws of artikel....

Ik hoop dat het zo wat duidelijker is.

Wat ik dus zou willen is dat ik als ik een $item (vanuit klasse Item) heb ik er een soort van type-case op zou kunnen gooien dat het een $artikel wordt. Dit gaat helaas niet, dat is me duidelijk. Beide van de 2 oplossingen die ik aangedragen heb werken, maar is er misschien een mooiere oplossing voor dit probleem?

[ Voor 14% gewijzigd door Myrdhin op 29-09-2003 22:23 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

drm: ik vermoed dat ie zoiets probeert:

PHP:
1
2
3
4
5
6
7
8
9
class Item
{
    Item ($id)
    {
        $result = mysql_query ("SELECT * FROM items WHERE id=" . $id);
        $row = mysql_fetch_array ($result);
        // initializeer item
    }
}


en ja, dat is de verkeerde aanpak, want je kunt nou eenmaal geen Item instantieren als het vervolgens iets anders blijkt te zijn. Ik zou het met een static methode doen oid (heb je die in php?)

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Item
{
    static function getItem ($id)
    {
        // database afhandeling hier
        switch ($row["type"])
        {
            case TYPE_NEWSITEM:
                return new NewsItem ($row);

            case TYPE_ARTICLE:
                return new Article ($row);
        }
    }
}


$item = Item::getItem (23);



.edit: beetje spuit 11 :Y)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Myrdhin
  • Registratie: April 2000
  • Laatst online: 16:53
static functions heb je volgens mij niet in PHP. Wel static variabelen.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

oh, even in de manual gekeken. Normale memberfunctions kunnen ook als static worden aangeroepen (:r)

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
class A
{
    function func ()
    {
        echo "A::func ()";
    }
}

A::func ();   // ok

$a = new A ();
$a->func ();  // ok

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06 13:31

drm

f0pc0dert

Dat is een andere discussie, .oisyn ;) Met PHP5 wordt de wereld een stuk beter. Of we moeten gewoon allemaal PHP afschaffen en op servlets overstappen ofzo, maar goed, zoals gezegd, da's een andere discussie :P

Wat volgens mij de beste oplossing is, is door middel van een soort van factory-achtige class te werken. Ik doe dat nogal 's met formuliertjes e.d. en in een CMS maak ik er ook gebruik van. 't Is niet echt wat je zegt hoogdravend design maar flexibel is het zeker:

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class ItemFactory {
   function ItemFactory () {
      trigger_error ( "Cannot create instance of factory ItemFactory" );
   }

   function &getInstance ( $db, $id ) {
      $className = $db->getItemTypeClassName ( $id );
      if ( ! class_exists ( $className ) ) {
         trigger_error ( "Unknown type $className, cannot instantiate in ItemFactory::getInstance ()" );
         return null;
      } else {
          $ret = new $className ( $id, $db );
      }
   }
}

class MyTypeDatabase extends Database {
    function MyTypeDatabase ( ... ) {
       Database::Database ();
       // ...
    }

    function getItemTypeClassName ( $id ) {
       // determine itemtype
       switch ( ... ) {
          ...
          case ... :
              return 'NewsItem';
          case  ...:
              return 'ArticleItem';
          default:
              return 'Item';
       }
    }
}

class NewsItem extends Item {
   function NewsItem ( $id, $db ) {
      Item::Item ( $id, $db ) // let Item do its init thing
       
      $this->a = $db->getAllKindsOfStuffAboutThisItem ( ... );
   }
}

$db = new MyTypeDatabase ();
$item = ItemFactory::getInstance ( $db, $id );

echo "Woei, we hebben een " . get_class ( $item ) . " kunnen creeeren!!!11";


Ik zuig 't nu even uit m'n duim, maar 't is een manier. 't Is om meerdere redenen niet echt een mooie manier, maar ach...

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik vond mijn voorbeeld duidelijker en korter ;)
(en btw, Orbb beats PHP5 in no-time :Y))

[ Voor 31% gewijzigd door .oisyn op 30-09-2003 00:35 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06 13:31

drm

f0pc0dert

.oisyn:
Ik vond mijn voorbeeld duidelijker en korter ;)
Euh tja, mijn interne php-parser bleef steken bij die 'static' denk ik :+

lees: niet goed gelezen |:(
(en btw, Orbb beats PHP5 in no-time :Y))
you've got my vote :P

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


Acties:
  • 0 Henk 'm!

  • Myrdhin
  • Registratie: April 2000
  • Laatst online: 16:53
drm schreef op 30 September 2003 @ 00:33:
Dat is een andere discussie, .oisyn ;) Met PHP5 wordt de wereld een stuk beter. Of we moeten gewoon allemaal PHP afschaffen en op servlets overstappen ofzo, maar goed, zoals gezegd, da's een andere discussie :P

Wat volgens mij de beste oplossing is, is door middel van een soort van factory-achtige class te werken. Ik doe dat nogal 's met formuliertjes e.d. en in een CMS maak ik er ook gebruik van. 't Is niet echt wat je zegt hoogdravend design maar flexibel is het zeker:

[knip] stukje code [/knip]

Ik zuig 't nu even uit m'n duim, maar 't is een manier. 't Is om meerdere redenen niet echt een mooie manier, maar ach...
Het is wel de oplossing waar ik naar op zoek was. Ik dacht alleen dat het designtechnisch mooier was om een type class, bv. item of nieuwsitem, te laten praten met de juiste tabel in de database, in een soort van 1 op 1 relatie

Dit is blijkbaar niet van belang in het ontwerp van klassen (ik ben hier nog niet zo lang mee bezig, mijn enige echte ervaring met OO programmeren is met Borland Pascal).

Ik ga die Factory methode eens wat beter bekijken, zag 'm ook al staan op phppatterns.com. Bedankt voor jullie duwtje in de goede richting.

[ Voor 4% gewijzigd door Myrdhin op 30-09-2003 07:35 ]

Pagina: 1