Class instantieren met variabel aantal parameters

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Erwin H

Erwin H

11/12/2012 00:05:18
Quote Anchor link
Het instantieren van een class is op zich natuurlijk geen punt waar ik normaal gesproken nog over nadenk. Ook het instantieren van een class waarvan ik design time de naam nog niet weet is dat niet. Alleen kom ik in mijn factories en service containers nu tig keer het volgende tegen:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?php
try{
  $obj = new $classname();
  //do something
  return $obj;
}
catch( Exception $e ){
  throw new FactoryException( 'some message' );
}

?>

Aangezien ik niet van te vaak hetzelfde intikken houd, moet dit volgens mij beter kunnen. Wat ik dus eigenlijk wil doen is een instantiator class bouwen die het daadwerkelijk instantieren voor zijn rekening neemt. Ik geef classname, parameters en foutmelding mee en die instantiator class geeft me een object terug.

Maar.... hoe nu parameters meegeven en daadwerkelijk in het instantieren van die class verwerken? Sommige classes hebben geen constructor, andere hebben wel een constructor maar geen parameters, weer andere hebben tussen 1 en veel parameters (in theorie in elk geval veel). Een manier zou dit zijn:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
switch( count( $args ) ){
  case
0:
    $obj = new $classname();
    break;
  case
1:
    $obj = new $classname( $args[0] );
    break;
  //etc etc
}
?>

Maar hoever ga je dan, tot de 20? Niet echt flexibel als je het mij vraagt.

Een andere manier die ik tegenkwam was het gebruik van de ReflectionClass:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
$reflect
= new ReflectionClass( $classname );
$obj = $reflect->newInstanceArgs( $args );
?>

Alleen geeft dit weer een foutmelding als de class die wordt geinstantieerd geen constructor heeft. Dan zal je voor die classes dus alweer een alternatief moeten hebben (of via het afvangen van de foutmelding de andere manier toepassen). Of misschien wel meerdere mogelijkheden in de instantiator class bouwen waarbij de factory zelf kan bepalen welke gekozen wordt.

Iemand enige ervaring met deze materie, tips, hints, oplossingen?
Gewijzigd op 11/12/2012 00:07:07 door Erwin H
 
PHP hulp

PHP hulp

28/11/2024 08:43:34
 
Wouter J

Wouter J

11/12/2012 07:47:13
Quote Anchor link
Ik ben ook bezig met een service container en daar gebruik ik de ReflectionClass. Je kan de constructor opvragen met getConstructor en zo wat leuke dingen doen:
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
<?php

public function initializeObject($classname, array $arguments, $errorMessage)
{

    $reflection = new \ReflectionClass($classname);
    $constructor = $reflection->getConstructor();

    if (null === $constructor) {
        // no constructor, instantiate
        $obj = $reflection->newInstance();
    }
else {
        // it has a constructor, get the minimal count of parameters
        $count = $constructor->getNumberOfRequiredParameters();

        if (0 == $count) {
            $obj = $reflecton->newInstance();
        }
elseif ($count <= count($arguments) {
            $obj = $reflection->newInstanceArgs($arguments);
        }
else {
            throw new \InvalidArgumentException(
                sprintf(
                    'Cannot initialize the %s class, expected %d arguments %d given',
                    $classname,
                    $count,
                    count($arguments)
                )
            );
        }
    }
}
 
Erwin H

Erwin H

11/12/2012 09:06:10
Quote Anchor link
Probleem opgelost :-)

Ik had dus toch nog even dieper moeten graven in die ReflectorClass. Dat je ook specifieke info over de constructor kon krijgen op die manier was ik nog niet achter gekomen. Op die manier is het wel wat nodig is en kan ik doen wat ik wil.

Thanks!
 
- Raoul -

- Raoul -

11/12/2012 16:05:16
Quote Anchor link
Bestaat er zoiets als een ReflectionClass? Geweldig, ga ik gebruiken voor het inladen van controllers want ik doe nu alles met call_user_func
Gewijzigd op 11/12/2012 16:05:43 door - Raoul -
 
Wouter J

Wouter J

11/12/2012 16:10:26
Quote Anchor link
Ja, er bestaat een hele Reflection library waarmee je alles te weten kunt komen over klassen, methods, properties, parameters, ect. Zeker de moeite waard om te bekijken.

Deze library wordt bijv. gebruikt in PHPdocumentor om de PHPdocs te krijgen en in Silex en Symfony om placeholders in je url te verwerken in parameters van functies:
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
<?php
// ...

$app->match('/post/{id}/{slug}', function ($id, $slug) {
});

// is hetzelfde als
$app->match('/post/{id}/{slug}', function ($slug, $id) {
});

// doordat je met de Reflection library de name van parameters kunt krijgen

// zelfs dit kan:

$app->match('/post/{id}/{slug}', function (\Silex\Application $app, $slug, $id) {
});

?>
 
- Raoul -

- Raoul -

11/12/2012 16:12:29
Quote Anchor link
Hmm, dat gaat mijn dispatching zeker netter maken.

Ipv dit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php
$className
= "\\" . ucfirst($namespace) . "\\Controller\\" . ucfirst($controllerName . 'Controller');
$methodName = $dispatching[2];
$instance = new $className($container, $request);
                    
$response = call_user_func_array(array($instance, lcfirst($methodName) . 'Action'), $routeMatches);
?>


Is het trouwens mogelijk om bijvoorbeeld arguments die je passed een bepaalde naam geven?

Bv dit: $reflection->callMethod('postAction', array(
'id' => $matches['id']
);
Gewijzigd op 11/12/2012 16:13:39 door - Raoul -
 
Erwin H

Erwin H

12/12/2012 13:28:32
Quote Anchor link
Overigens merkte ik dat er een klein probleempje zit in de code die Wouter gaf en wil in dit deel:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?php
        $count
= $constructor->getNumberOfRequiredParameters();

        if (0 == $count) {
            $obj = $reflecton->newInstance();
        }
elseif ($count <= count($arguments) {
            $obj = $reflection->newInstanceArgs($arguments);
        }

?>

Het probleem zit hem in classes die wel een constructor hebben, met parameters, maar wanneer alle parameters een default waarde hebben. In dat geval is het aantal required parameters 0 ($count = 0) en wordt de class geinstantieerd via $reflecton->newInstance(). Heb je echter wel parameters meegegeven, dan worden die dus niet meegenomen in het instantieren.

Wat bij mij nu wel correct werkt is dit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?php
        $countReq
= $constructor->getNumberOfRequiredParameters();
        $countParam = $constructor->getNumberOfParameters();

        if (0 == $countParam) {
            $obj = $reflecton->newInstance();
        }
elseif ($countReq <= count($arguments) {
            $obj = $reflection->newInstanceArgs($arguments);
        }

?>
Gewijzigd op 12/12/2012 13:28:46 door Erwin H
 



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.