Class instantieren met variabel aantal parameters
Code (php)
1
2
3
4
5
6
7
8
9
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' );
}
?>
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)
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)
1
2
3
4
2
3
4
<?php
$reflect = new ReflectionClass( $classname );
$obj = $reflect->newInstanceArgs( $args );
?>
$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
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
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)
)
);
}
}
}
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)
)
);
}
}
}
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!
Gewijzigd op 11/12/2012 16:05:43 door - Raoul -
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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) {
});
?>
// ...
$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) {
});
?>
Ipv dit:
Code (php)
1
2
3
4
5
6
7
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);
?>
$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 -
Code (php)
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)
Gewijzigd op 12/12/2012 13:28:46 door Erwin H