Class in een class

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Pagina: 1 2 volgende »

Ruben Portier

Ruben Portier

23/12/2012 22:14:43
Quote Anchor link
Beste

Ik ben bezig met een website waarbij ik aardig gebruik maak van OOP. Daarbij heb ik nu het probleem dat ik een bepaalde class in een andere class moet gebruiken. Ik wil niet opnieuw een object aanmaken omdat ik dan weer een 'leeg' object heb. Ik wil namelijk een bestaand object (die aangemaakt is buiten de class) gebruiken in een class.

Voorbeeldje om het wat te verduidelijken

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class class1 {
     private $data;

     function functie1($data) {
          $this->date = $data;
     }
}

$class1 = new class1;

class class2 {
     function functie2($data) {
          return $class1->functie1($data);
     }
}


Ik weet nu al bijna zeker dat het op bovenstaande manier niet zal werken. Weet er toevallig iemand hoe je dit kan oplossen?

Bedankt alvast!

Toevoeging op 23/12/2012 22:33:36:

Ik heb net iets gevonden waarmee ik het zou kunnen proberen. Met de singleton patern. Iemand die weet of dat goed en veilig is?
 
PHP hulp

PHP hulp

22/12/2024 09:21:44
 
Wouter J

Wouter J

23/12/2012 22:33:41
Quote Anchor link
Gewoon zoals je altijd een parameter van buiten een functie in een functie brengt:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
$class1
= new Class1();
$class2 = new Class2();
$class2->functie2($class1);
?>


Tevens raad ik je aan eens te kijken naar Dependency Injection: http://www.phphulp.nl/php/tutorial/classes/dependency-injection/760/


PS: Ik ben totaal geen voorstander van het Singleton pattern en dat is hier zeker niet voor nodig.
Gewijzigd op 23/12/2012 22:42:01 door Wouter J
 
Ruben Portier

Ruben Portier

23/12/2012 22:49:01
Quote Anchor link
Bedankt voor je reactie! Dependency injection is zoals ik het nu heb. Maar ik vond het nogal een 'vreemde' manier van werken. Ik moet dan telkens bij alle classes die b.v. de database class moeten kunnen bereiken een $db var toevoegen een de __constructor van die class.

Is dit dan echt de enige goede manier? En waarom is singleton slecht?
 
Wouter J

Wouter J

23/12/2012 23:04:27
Quote Anchor link
Quote:
Is dit dan echt de enige goede manier?

De 'enige goede' durf ik niet te zeggen, het is een van de meest recentste patternen in PHP wereld en wordt langzamerhand door alle grote libraries gebruikt.

Met een Service Container voorkom je problemen met het telkens moeten toevoegen van de $db parameter. Kijkt bijv. maar eens naar dit simpele voorbeeld:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
$container
= new Pimple();

$container['database.class'] = 'Wj\Storage\MySQLiDatabaseStorage';
$container['database.settings'] = array(
    'user' => 'root',
    'pass' => 'foobar',
    'host' => 'localhost',
    ...
);

$container['database'] = function ($c) {
    $settings = $c['database.settings'];

    return new $c['database.class']($settings['host'], $settings['user'], ...);
};


$container['user.mapper.class'] = 'Wj\User\UserMapper';
$container['user.mapper'] = $container->share(function ($c) {
    return $c['user.mapper.class']($c['database']);
});


// in gebruik
$user = $container['user.mapper']->findById(2);
$user1 = $container['user.mapper']->findByName('Henk');
?>


Quote:
En waarom is singleton slecht?

Doordat je maar 1 instance per request kan hebben. Dat houdt elke vorm van Test Driven Development en elke vorm van uitbreiding tegen.
Gewijzigd op 23/12/2012 23:05:28 door Wouter J
 
- Raoul -

- Raoul -

24/12/2012 07:16:06
Quote Anchor link
Je kunt natuurlijk ook met getters and setters werken.

->setClass1($class)
->getClass1()

Maar zoals Wouter zegt is DI een betere methode.
 
Wouter J

Wouter J

24/12/2012 11:10:15
Quote Anchor link
Raoul, setters is ook een vorm van Injection. Je hebt 3 vormen: Constructor injection, Property injection en setter injection. Property injection wordt zelden gebruikt en als een klasse iets per se nodig heeft gebruik je constructor en anders setter.
 
- Raoul -

- Raoul -

24/12/2012 13:21:19
Quote Anchor link
Ah zo, weer iets bijgeleerd :))
 
Ruben Portier

Ruben Portier

24/12/2012 13:32:58
Quote Anchor link
Bedankt allemaal! Ik snap de code van Wouter J niet zo goed. Het lijkt me nogal veel code. Bij singleton kan ik dan misschien maar 1 instance per request doen. Dat is ook net wat ik wil. Stel ik heb een database class. Dan wil ik toch ook maar 1 instance van die database aanmaken en niet met 5 verschillende database connecties gaan rondlopen?

Is singleton daarvoor toch geen goed idee?
 
- Raoul -

- Raoul -

24/12/2012 13:43:39
Quote Anchor link
Wouter gaf puur een voorbeeld. Wat wil je nu precies doen eigenlijk?
Ik denk wel dat DI voor een simpele applicatie en een beginner als jouw een beetje uitgebreid is... dus daarom toon ik even mijn getter en setter voorbeeldje:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php

class EersteClass
{

}


class TweedeClass
{
  private $_eersteClass;

  public function setEersteClass(EersteClass $eerst)
  {

    $this->_eersteClass = $eerst;
  }


  public function getEersteClass()
  {

    return $this->_eersteClass;
  }


  public function voorbeeldje()
  {

    $class = $this->getEersteClass();
    // doe iets met $class
  }
}


$eersteClass = new EersteClass();
$tweedeClass = new TweedeClass();

$tweedeClass->setEersteClass($eersteClass);

?>


Als je van plan bent om meerdere classen te hebben die ook EersteClass gebruiken kan je misschien ook werken met Aware classen?

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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

abstract class EersteClassAware
{
  private $_eersteClass;

  public function setEersteClass(EersteClass $eerst)
  {

    $this->_eersteClass = $eerst;
  }


  public function getEersteClass()
  {

    return $this->_eersteClass;
  }
}


class EersteClass {}

class TweedeClass extends EersteClassAware {}
class DerdeClass extends EersteClassAware {}

$eersteClass = new EersteClass();

$tweede = new TweedeClass();
$derde = new DerdeClass();

$tweede->setEersteClass($eersteClass);
$derde->setEersteClass($eersteClass);

?>
Gewijzigd op 24/12/2012 13:47:21 door - Raoul -
 
Ruben Portier

Ruben Portier

24/12/2012 13:51:50
Quote Anchor link
Bedankt Raoul! Maar ik snap niet waarom je in bovenstaande code dan ook een class EersteClass aanmaakt. En dan moet ik dus telkens (zoals ik het nu al heb) de al reeds aangemaakte object meegeven.

Ik heb dus een database class aangemaakt. Dan maak ik bovenaan in mijn index file het database-object aan door volgende code uit te voeren:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
$db = new mysql($host, $user, $pass, $database);


Het probleem is nu dat ik het $db object ook in een andere class (user) wil gebruiken.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
class user {
  __constructor() {
    $this->db = $db; // Hoe verkrijg ik hier de reeds aangemaakte $db object?
  }
}


Wat ik nu heb is als volgt:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
class user {
  __constructor($db) {
    $this->db = $db; // Hoe verkrijg ik hier de reeds aangemaakte $db object?
  }
}

$db = new mysql($host, $user, $pass, $database);
$user = new user($db);


Ik wil nu juist net niet die $db meesturen naar de constructor van de user class. Dit lijkt mij nogal vreemd om te doen. Net omdat ik dan bij iedere class waar ik die database nodig heb dat moet bijvoegen.
 
- Raoul -

- Raoul -

24/12/2012 15:04:12
Quote Anchor link
Wat je hierboven doet is gewoon normale OO en is gewoon correct, hoe vreemd je dat ook vind.
Je code is wel niet echt net...

Hieronder verbeterd:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php

class User
{
  public $db = null;
  public $id = null;

  public function __construct($db, $id)
  {

    $this->db = $db;
    $this->id = $id;
  }


  public function getUsername()
  {

    $user = $this->db->query('...');

    return $user->fetch()['username'];
  }
}

$db = new Db(...);

$user = new User(1, $db);

echo $user->getUsername();

?>


Toevoeging op 24/12/2012 15:05:21:

Lees anders even deze OOP tutorial: http://phptuts.nl/view/45/ ?
Gewijzigd op 24/12/2012 15:06:37 door - Raoul -
 
Ruben Portier

Ruben Portier

24/12/2012 15:06:22
Quote Anchor link
- Raoul - op 24/12/2012 15:04:12:
Wat je hierboven doet is gewoon normale OO en is gewoon correct, hoe vreemd je dat ook vind.
Je code is wel niet helemaal net, je zet geen 'public function' voor je methods.

Hieronder verbetert:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php

class User
{
  public $db = null;
  public $id = null;

  public function __construct($db, $id)
  {

    $this->db = $db;
    $this->id = $id;
  }


  public function getUsername()
  {

    $user = $this->db->query('...');

    return $user->fetch()['username'];
  }
}

$db = new Db(...);

$user = new User(1, $db);

echo $user->getUsername();

?>


Toevoeging op 24/12/2012 15:05:21:

Lees anders even deze OOP tutorial: http://phptuts.nl/view/45/ ?


Bedankt! Ik zal het dan op deze manier verder doen. Ik zet wel private en public voor mijn functies. Maar het voorbeeld was even 'snel' getypt hier. Geen exacte kopie van wat ik heb in mijn bestanden.

Heel erg bedankt iedereen!
 
Rick van Riel

Rick van Riel

24/12/2012 15:44:08
Quote Anchor link
Ruben,

De meeste makkelijke oplossing is volgens mij op elke class waarin je een database connectie willen gebruiken te extenden met de database class.

Je krijgt dan dit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

include('path/to/db.class.php');

class User extends Db {

  public function getUsername($id) {

    $result = $this->query("SELECT * FROM users WHERE id = ".$id);
    return $result->fetch();

  }

}


$user = new User;
print_r($user->getUsername());

?>


De grotere frameworks doen het ook op deze manier omdat het gewoon snel en overzichtelijk werkt.
 
Ruben Portier

Ruben Portier

24/12/2012 16:06:33
Quote Anchor link
Rick van Riel op 24/12/2012 15:44:08:
Ruben,

De meeste makkelijke oplossing is volgens mij op elke class waarin je een database connectie willen gebruiken te extenden met de database class.

Je krijgt dan dit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

include('path/to/db.class.php');

class User extends Db {

  public function getUsername($id) {

    $result = $this->query("SELECT * FROM users WHERE id = ".$id);
    return $result->fetch();

  }

}


$user = new User;
print_r($user->getUsername());

?>


De grotere frameworks doen het ook op deze manier omdat het gewoon snel en overzichtelijk werkt.


Bedankt, maar wat als je dan meerdere classes wil 'includen' in een andere class. Ik heb b.v. een class database, error en user. Ik wil in user de class database en error kunnen aanroepen. Kan dit wel met extend?
 
- Raoul -

- Raoul -

24/12/2012 16:22:19
Quote Anchor link
Rick van Riel op 24/12/2012 15:44:08:
Ruben,

De meeste makkelijke oplossing is volgens mij op elke class waarin je een database connectie willen gebruiken te extenden met de database class.

Je krijgt dan dit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

include('path/to/db.class.php');

class User extends Db {

  public function getUsername($id) {

    $result = $this->query("SELECT * FROM users WHERE id = ".$id);
    return $result->fetch();

  }

}


$user = new User;
print_r($user->getUsername());

?>


De grotere frameworks doen het ook op deze manier omdat het gewoon snel en overzichtelijk werkt.


Nee, de meeste frameworks doen het niet zo en gebruiken DI.
 
Wouter J

Wouter J

24/12/2012 16:28:37
Quote Anchor link
Neeneeneeneeneeeeee, niet doen Rick! Met Extenden maak je een IS_EEN relatie, je mag alleen extenden als je een klasse uitbreid. Bijv. Admin extends User, want Admin IS_EEN User of Cat extends Animal, want Cat IS_EEN Animal. Maar een User is geen vorm of uitbreiding van Database, User IS_GEEN Database maar User HEEFT_EEN database. Al is dat officieel niet goed en zul je een UserMapper hebben die een database HEEFT, maar goed dat laten we buiten beschouwing. Het hoofddoel is dat je nog mag extenden om deze rede!

En je mag mij een framework laten zien die dat op deze manier doet. Tevens zijn frameworks nooit gemaakt om 'snel' te werken, maar juist om 'goed en mooi volgens de standaarden' te werken. Als laatst is dit niet overzichtelijk, aangezien je op deze manier niet meerdere 'dependencies' kan hebben.
Gewijzigd op 24/12/2012 16:29:18 door Wouter J
 
Moose -

Moose -

24/12/2012 17:58:13
Quote Anchor link
Wat ook een optie is, is werken met een static variable: http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static

Voorbeeldje:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
class Database {
    static $instance;
    public static function getInstance() {
        if (null === self::$instance) {
            self::$instance = new PDO(...);
        }

        return self::$instance;
    }
}


class Model {
    protected $db;
    public function __construct() {
        $this->db = Database::getInstance();
    }
}


class User extends Model {
    public function getUsername($id) {
        // je kan hier $this->db aanroepen
    }
}

?>


Ik vind het zelf ook redelijk vervelend om steeds een database object via de constructor mee te geven, en dan is dit een oplossing waarmee alles wat soepeler gaat. Ik ben benieuwd wat de rest van zoiets ^ vind
Gewijzigd op 24/12/2012 18:00:52 door Moose -
 
Wouter J

Wouter J

24/12/2012 19:26:14
Quote Anchor link
Not Moose, dat is het singleton pattern. In dit geval kun je dus maar 1 database connectie gebruiken in je hele request, je krijgt telkens dezelfde instance. Hierdoor maak je Test driven Development onmogelijk.

En denk nu eens over het gebruik van deze applicatie op een host zonder database? Dan moet je bijv. een FileDatabase klasse gaan gebruiken en mag je al je models aanpassen.

Tevens vind ik User geen model, UserModel of UserMapper daarintegen wel.
 
- Raoul -

- Raoul -

24/12/2012 19:26:43
Quote Anchor link
Ga nu alsjeblieft niet werken met singletons en beginners de verkeerde manier aanleren.
 
Moose -

Moose -

24/12/2012 20:44:54
Quote Anchor link
Ik denk niet dat OP de intensie heeft om tests te implementeren in zijn script. Ook denk ik niet dat hij een filedatabase gaat gebruiken in plaats van een sql database. Overigens ben je met PDO al redelijk goed bezig op dat opzicht.

Singleton is een oplossing, en het is/was populair voor een reden. Het is niet een verkeerde manier, het is een manier.

Ik denk dat jullie alles een beetje aan het overdenken zijn, zeker aangezien de vragen die de OP stelt. Als hij nooit singleton gaat gebruiken, zal hij ook nooit achter de sterke/zwakke punten komen :)
 
Ger van Steenderen
Tutorial mod

Ger van Steenderen

24/12/2012 20:47:51
Quote Anchor link
Ik ben een grote voorstander van OOP, maar ik vraag me af of dat in PHP vaak meer als een doel dan als een middel beschouwd wordt.
Om Wouters voorbeeld van een user aan te halen, wat ga je doen als je 6 verschillende type users hebt, ga je dan voor elke type user de user class extenden? Nee toch?
 

Pagina: 1 2 volgende »



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.