[PHP]override method with variable args from abstract class

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • marty
  • Registratie: Augustus 2002
  • Laatst online: 27-03-2023
Ik probeer een method uit een abstracte class the overriden waarbij ik ook de parent-method aan wil roepen.
De reden dat ik dit doe is dat de abstracte classe in een framework zit die ik dus niet aan kan passen en ik wil wat logging toevoegen op het moment dat die functie wordt aangesproken.
Het probleem is echter dat de method werkt met variabele argumenten en ik het niet voor elkaar krijg deze argumenten op een nette manier door te geven.

een versimpelde weergave van wat ik geprobeerd heb:

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
abstract class Base
{
     public function find()
    {
        $args = func_get_args();
        echo __METHOD__." was called with ".count($args)." arguments: ".print_r($args, true)."<br>\n"; 
    }
}

class Real extends Base
{
    public function find()
    {
        $args = func_get_args();
        echo __METHOD__." was called with ".count($args)." arguments: ".print_r($args, true)."<br>\n";

        parent::find(func_get_args());

        $method = new ReflectionMethod("Base", "find");

        $method->invokeArgs(new Base(), $args);
    }
}

$real = new Real();
$real->find(1, 2, 3);


dit geeft de volgende output:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Real::find was called with 3 arguments: Array
(
    [0] => 1
    [1] => 2
    [2] => 3
)


Base::find was called with 1 arguments: Array
(
    [0] => Array
        (
            [0] => 1
            [1] => 2
            [2] => 3
        )
)

Fatal error:  Cannot instantiate abstract class Base


Deze output had ik ook wel verwacht, daar niet van, maar het leek me zinvol te vermelden dat dit dus niet werkt.

De enige oplossingen die ik kan verzinnen:
  1. Met een switch statement werken en afhankelijk van count($args) de parent met bvb find($args[0], $args[1]) aanroepen.
  2. Door $args loopen en de argumenten als php-code maken en dan met eval gaan werken.
Beide oplossingen werken, maar vind ik niet erg mooi.
Kan iemand iets beters bedenken? Wellicht dat de Reflection classes toch op een andere manier uitkomst bieden?

Acties:
  • 0 Henk 'm!

  • Flying_Thunder
  • Registratie: December 2001
  • Niet online
Via call_user_func_array() ? http://nl2.php.net/manual....call-user-func-array.php
In Real::find zet je
call_user_func_array(array($this, 'parent::find'), $args); :)

Acties:
  • 0 Henk 'm!

  • Joolee
  • Registratie: Juni 2005
  • Niet online
Zo te zien wordt op lijn 17 al Base::find uitgevoerd. Komt er van regel 21 nog enige output? Ik neem aan dat het de bedoeling is dat daar pas Base::find wordt uitgevoerd met de juiste argumenten?

Acties:
  • 0 Henk 'm!

  • marty
  • Registratie: Augustus 2002
  • Laatst online: 27-03-2023
Flying_Thunder schreef op dinsdag 21 september 2010 @ 10:28:
Via call_user_func_array() ? http://nl2.php.net/manual....call-user-func-array.php
In Real::find zet je
call_user_func_array(array($this, 'parent::find'), $args); :)
find is geen statische methode, dus zo aanroepen (afgezien van dat je dat volgens mij niet met 'parent' kan doen - maar dat terzijde), zal zowiezo niet gaan. Ook het doorgeven van een object aan die functie zal niet lukken, want je kan immers geen instantie maken van een abstracte classe - hetzelfde probleem als waar ik bij reflectie tegen aan loop.
Joolee schreef op dinsdag 21 september 2010 @ 10:28:
Zo te zien wordt op lijn 17 al Base::find uitgevoerd. Komt er van regel 21 nog enige output? Ik neem aan dat het de bedoeling is dat daar pas Base::find wordt uitgevoerd met de juiste argumenten?
de code hierboven is slechts een voorbeeld van dingen die _niet_ lukken, om de suggesties voor te zijn ;)
(de output van regel 21 is overigens de fatal error)

Acties:
  • 0 Henk 'm!

  • Joolee
  • Registratie: Juni 2005
  • Niet online
Op PHP.net staan ook nog enkele suggesties
mrextreme at freemail dot hu 07-Dec-2009 04:34
If you are using PHP < 5.3 and want to call the parent class' __construct() with a variable parameter list, use this:
PHP:
1
2
3
4
5
6
7
<?php 
public function __construct() 
{ 
    $vArgs = func_get_args(); // you can't just put func_get_args() into a function as a parameter 
    call_user_func_array(array('parent', '__construct'), $vArgs); 
} 
?> 
dmitry dot revenko at businessmedia dot ru 25-Sep-2009 12:28
Just hope this note helps someone (I killed the whole day on issue).

If you use something like this in PHP < 5.3:
PHP:
1
<?php call_user_func_array(array($this, 'parent::func'), $args); ?> 

Such a script will cause segmentation fault in your webserver.

In 5.3 you should write it:
PHP:
1
<?php call_user_func_array('parent::func', $args); ?> 
levi at alliancesoftware dot com dot au
08-Feb-2007 10:50

Regarding the comments below about calling parent constructors:

PHP5 with E_STRICT no longer allows calls as below:

PHP:
1
2
3
4
<?php 
// Causes an error with E_STRICT 
call_user_func_array(array('parent', '__construct'), $args); 
?> 


It gives an error because you are trying to call a nonstatic function as if it was static. The correct syntax is

PHP:
1
2
3
4
<?php 
// Works fine 
call_user_func_array(array($this, 'parent::__construct'), $args); 
?>

Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
marty schreef op dinsdag 21 september 2010 @ 10:44:
[...]


find is geen statische methode, dus zo aanroepen (afgezien van dat je dat volgens mij niet met 'parent' kan doen - maar dat terzijde), zal zowiezo niet gaan. Ook het doorgeven van een object aan die functie zal niet lukken, want je kan immers geen instantie maken van een abstracte classe - hetzelfde probleem als waar ik bij reflectie tegen aan loop.
Als je het nu eerst eens probeert in plaats van te zeggen dat het zowiezo sowieso niet zal gaan, dan zul je er achter komen dat het wél werkt.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
abstract class Base 
{ 
    public function find() 
    { 
        $args = func_get_args(); 
        echo __METHOD__." was called with ".count($args)." arguments: ".print_r($args, true)."<br>\n";  
    } 
} 

class Real extends Base 
{ 
    public function find() 
    { 
        $args = func_get_args(); 
        echo __METHOD__." was called with ".count($args)." arguments: ".print_r($args, true)."<br>\n"; 
        
        call_user_func_array(array($this, 'parent::find'), $args);
    } 
} 

$real = new Real(); 
$real->find(1, 2, 3);


Real::find was called with 3 arguments: Array
(
    [0] => 1
    [1] => 2
    [2] => 3
)

Base::find was called with 3 arguments: Array
(
    [0] => 1
    [1] => 2
    [2] => 3
)

[ Voor 39% gewijzigd door HuHu op 21-09-2010 10:58 ]


Acties:
  • 0 Henk 'm!

  • marty
  • Registratie: Augustus 2002
  • Laatst online: 27-03-2023
excuus, ik had $this over het hoofd gezien in de post van Flying_Thunder en dacht dat het gewoon een static call naar de parent-method betrof (wat uiteraard niet gewerkt had).

de combinatie van $this en parent::method kende ik niet! maar hij werkt perfect! bedankt.
Pagina: 1