te veel functie parameters
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
abstract class basis {
protected function _fout($k) {
trigger_error('Eigenschap "' . $k . '" van object "'
. get_class($this) . '" bestaat niet of is niet publiek.');
}
function __get(string $k) {$this->_fout($k);}
function __set(string $k, $v) {$this->_fout($k);}
}
class test extends basis {
function __construct() {}
}
$uit = new test('ik wil hier een error op');
?>
abstract class basis {
protected function _fout($k) {
trigger_error('Eigenschap "' . $k . '" van object "'
. get_class($this) . '" bestaat niet of is niet publiek.');
}
function __get(string $k) {$this->_fout($k);}
function __set(string $k, $v) {$this->_fout($k);}
}
class test extends basis {
function __construct() {}
}
$uit = new test('ik wil hier een error op');
?>
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class test_extends basis
{
function __construct()
{
$numargs = func_num_args();
if($numargs > 0) {
throw new Exception('too many arguments');
}
}
}
new test(1, 2, 3);
?>
class test_extends basis
{
function __construct()
{
$numargs = func_num_args();
if($numargs > 0) {
throw new Exception('too many arguments');
}
}
}
new test(1, 2, 3);
?>
https://www.php.net/manual/en/function.func-num-args.php
Ik had ooit een functie met meerdere argumenten:
En na refactoren werd dat
Maar ergens was ik vergeten de functie-call te wijzigen en bleef dit staan:
$x->y($a, $b); // geen error...
En toen bedacht ik me dat je in PHP altijd meer argumenten kan geven dan een functie aankan.
Het zou mooi zijn als dat vanuit de basisklasse kan worden opgelost, zodat mijn code meer strikt wordt.
https://stackoverflow.com/questions/58529387/php-functions-more-arguments-than-expected
en
https://stackoverflow.com/questions/7928707/why-does-php-not-throw-an-error-when-i-pass-too-many-parameters-to-a-function
Ad Fundum op 30/03/2022 08:55:14:
Goed idee van func_num_args(). Kan ik dat ook gebruiken in de base class voor elke functie?
Mja, even mijn vorige voorbeeld aangepast naar dit voorbeeld.
Maar eigenlijk moet je dit echt niet willen. Als je dit bij iedere functie-aanroep doet, zorgt dat voor veel onnodige controles en functie-aanroepen.
Ik zou zeggen, als je een functie achteraf wijzigt, zoek dan even waar die functie nog meer wordt gebruikt en pas 'm daar aan. Je bent nu een oplossing aan het bedenken voor iets wat zich in de praktijk ooit misschien een keertje voordoet, maar wat wel je code vertroebelt met vele extra controles en functie-aanroepen. Ik denk niet dat je dat moet willen.
Ik was al bang dat het moeilijk zou gaan, maar die SO-links helpen wel met
Code (php)
1
2
3
2
3
<?php
if(func_num_args()>count(get_defined_vars())) throw new Exception('Too many args.');
?>
if(func_num_args()>count(get_defined_vars())) throw new Exception('Too many args.');
?>
En de RFC (https://wiki.php.net/rfc/strict_argcount)
Heb je mijn voorbeeld ook gezien?
$rekenmachine = new Rekenmachine();
$rekenmachine->optellen(2, 5, 8, 34, 56, 104);
Daar mag je een aantal array's opgeven en die worden samengevoegd.
In de manual staat nu
array_merge(array ...$arrays): array
Maar een aantal PHP versies geleden was ...$array nog een onbekende syntax.
Daar kon je dus omheen door gewoon meerdere parameters mee te geven.
Ozzie PHP op 30/03/2022 11:42:22:
Ik denk dat dat inderdaad de enige juiste conclusie is. Overigens verbaast het me wel dat er geen warning wordt gegeven als er te veel argumenten worden meegegeven aan een functie.
Ik denk dat dat komt, omdat bij de ontwikkeling van PHP met een scheef oog naar Perl is gekeken.
Van oudsher werden in Perl de functie-parameters in een anonieme array doorgegeven:
Code (php)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
sub doe_iets
{
my $param1 = shift;
my $param2 = shift;
my @other_params = shift;
}
doe_iets('met', 'deze', 'tekst');
{
my $param1 = shift;
my $param2 = shift;
my @other_params = shift;
}
doe_iets('met', 'deze', 'tekst');
In principe waren alle parameters optioneel; als je de functie aanriep met doe_iets('doms') dan werd alleen $param1 gevuld en bleven $param2 en @other_params undefined. Op zich heel flexibel, maar het heeft wel als nadeel dat het lastig was om verplichte parameters af te dwingen. Daar kon je weliswaar function prototypes voor gebruiken, maar die werkten toch net iets anders dan je zou verwachten, vooral als je een taal als C gewend was.
Eigenlijk pas sinds 2015 ondersteunt Perl dit wat beter middels de (vooralsnog experimentele feature) subroutine signatures:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
sub doe_een_beetje ($param1)
{
}
sub doe_iets_meer ($param1, $param2 = 42, @other_params)
{
}
{
}
sub doe_iets_meer ($param1, $param2 = 42, @other_params)
{
}
Als je nu doe_een_beetje() aanroept met een verkeerd aantal parameters, krijg je een foutmelding. Bij doe_iets_meer() is $param1 verplicht, $param2 optioneel (met default-waarde 42) en @other_params slurpt alles op wat je verder nog aan parameters meegeeft.
PHP lijkt qua werking dus een beetje tussen de oudere en nieuwere Perl-versies te zitten.
Gewijzigd op 02/04/2022 13:14:19 door Willem vp
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
abstract class basis {
protected $f = [];
function __call(string $n, array $a) {
if (!isset($this->f[$n])) {trigger_error('Functie ' . $n . ' bestaat niet');}
if ((new ReflectionFunction($this->f[$n]))->getParameters()
!== count($a)) {trigger_error('Parameteraantal onjuist');}
call_user_func_array($this->f[$n], $a);
}
}
class test extends basis {
function __construct() {
$this->f = [ // functiedefinities vanaf hier
'functie' => function (string $a) {
print $a . PHP_EOL;
}
]; // tot hier
}
}
$t = new test;
$t->functie('A', 'B'); // error
?>
abstract class basis {
protected $f = [];
function __call(string $n, array $a) {
if (!isset($this->f[$n])) {trigger_error('Functie ' . $n . ' bestaat niet');}
if ((new ReflectionFunction($this->f[$n]))->getParameters()
!== count($a)) {trigger_error('Parameteraantal onjuist');}
call_user_func_array($this->f[$n], $a);
}
}
class test extends basis {
function __construct() {
$this->f = [ // functiedefinities vanaf hier
'functie' => function (string $a) {
print $a . PHP_EOL;
}
]; // tot hier
}
}
$t = new test;
$t->functie('A', 'B'); // error
?>
Eerder had ik class test zonder ctor:
Code (php)
Maar dat geeft een Fatal error: Constant expression contains invalid operations.
Gerelateerde info: https://www.sitepoint.com/community/t/pass-func-get-args-to-another-method-or-an-object/34653/10
Ad Fundum op 03/04/2022 09:01:44:
Dat je het niet moet willen betekent niet dat het niet kan.
Dat het kan had ik hier ook al laten zien. Maar je moet het inderdaad niet willen.
De enige oplossing die ik vond was niet geweldig. Anonieme functies in een array in combinatie met __call() werkt wel, maar ik ga er niet van uit dat m'n IDE het ook snapt, laat staan dat je iets kan met public, protected en private functies.
Ad Fundum op 05/04/2022 20:27:22:
De enige oplossing die ik vond was niet geweldig. Anonieme functies in een array in combinatie met __call() werkt wel ...
Nou, het was in ieder geval wel een creatieve poging :-)
EWD340
"De competente programmeur [...] vermijdt slimme truuks als de pest."
:-) Typisch gevalletje "De competente programmeur [...] vermijdt slimme truuks als de pest."