Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[PHP] Call naar functie in object geeft 'Fatal Error'

Pagina: 1
Acties:

Onderwerpen


  • Struikrover
  • Registratie: Juni 2005
  • Nu online
Hey Tweakers :),

Ik ben als hobbyist webdesigner begonnen me te oriënteren op het schrijven van PHP code op de OOP manier, zoals het in mijn ogen hoort en het meest overzichtelijk is.

Nu is OOP in elke programmeertaal wel iets anders geimplementeerd, zodat je kennis over het principe wel mee kunt nemen, maar de implementatie elke keer weer moet leren.
Ook twijfel ik bij dit probleem een beetje aan mezelf, omdat het al een hele poos geleden is dat ik fatsoenlijke code heb geproduceerd. Ben bang dat ik het wat verleerd ben ;).

Probleem
Bij het aanroepen van een functie uit een class vanuit een php document waarin ik die class geinstantieerd heb geeft PHP op 1 manier wel een Fatal Error en op de andere manier niet. Ik weet niet genoeg om het verschil te ontdekken.

Code
Ik heb een heel simpel voorbeeld gemaakt zodat een van jullie hopelijk gelijk kan zien wat hier mis is.

Dit is de class:
PHP: testClass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
    class testClass {
        
        function testClass() {
            //constructor
        }

        function doCount (){
            $countArray = array();
            for($i = 0; $i < 10; $i++){
                array_push($countArray,$i);
            }
            return $countArray;
        }
    }

?>


En dit is het php document dat het object instantieert en de functie aanroept:
PHP: testfile
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
    require_once("classes/testClass.php");

    $testclass = new testClass();

    $someArray = array();
    
    function countToTen(){
        $someArray = $testclass -> doCount();
    }
?>

<!DOCTYPE html>
<html lang="nl">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
        <title>Testfile</title>

    </head>
    
    <body>
        <?php
            countToTen();
            if(!empty($someArray)){
                var_dump($someArray);
            } else {
                echo 'Array is empty';
            }
        ?>
    </body>
</html>


Foutmelding
Bovenstaande code geeft de volgende foutmelding:
Fatal error: Call to a member function doCount() on a non-object in /..filepath../testfile.php on line 9
Ik begrijp dat het dus iets te maken heeft met het aanroepen van een functie (doCount) op een object wat op dat moment niet bestaat ($testclass). Echter, aan het begin van dat document heb ik dat object toch aangemaakt? De volgorde van aanroepen is IMO ook gewoon goed...

Het is wel zo dat dit wel goed gaat wanneer ik de regel:
PHP:
1
$someArray = $testclass -> doCount();

Gewoon in het PHP stuk in de body zet, dus zo:
PHP:
1
2
3
4
5
6
7
8
9
10
<body>
        <?php
            $someArray = $testclass -> doCount();
            if(!empty($someArray)){
                var_dump($someArray);
            } else {
                echo 'Array is empty';
            }
        ?>
    </body>


Oplossing?
Het is me wel duidelijk dat er iets mis gaat met het aanmaken van het $testclass object, maar ik zou niet weten hoe. Ik wil in principe in het begin van mijn document een class object aanmaken, eventueel met een aantal handelingen in de constructor, en dan later vanuit een php block in de body van mijn document een aantal functies in dat document kunnen aanroepen, die op hun beurt weer data uit functies van mijn class halen.

Lijkt me een normale werkwijze, maar goed. Ik hoor graag wat ik hier verkeerd doe :+.

  • spleethoven
  • Registratie: Oktober 2010
  • Laatst online: 24-01-2024
Constructors worden op deze manier geschreven in PHP:

PHP:
1
2
3
function __construct() {
       print "constructor\n";
   }

[ Voor 3% gewijzigd door MueR op 27-07-2011 11:44 . Reden: code tag gefixt :P ]


  • hostname
  • Registratie: April 2009
  • Laatst online: 26-11 23:34
Lees je eens in over de scope van objecten. Je maakt $testclass buiten de functie aan, en dus is deze niet beschikbaar in de functie countToTen()
spleethoven schreef op woensdag 27 juli 2011 @ 11:38:
Constructors worden op deze manier geschreven in PHP:

PHP:
1
2
3
function __construct() {
       print "constructor\n";
   }
De manier in de TS werkt ook (ja; PHP heeft 2 manieren om constructors te noemen...)

  • dygnus
  • Registratie: Mei 2008
  • Laatst online: 06-08 15:41
Het is erg simpel, je roept in een functie buiten de class de variabel '$testclass' aan. Binnen een functie kun je geen variabelen aanroepen, aanmaken of wijzigen die je buiten de functie weer kan gebruiken. Hiervoor kennen wij een return om waarden te gebruiken ;).

Om toch de variabelen $testclass en $someArray te gebruiken, moeten we deze als 'global' definiëren in de functie countToTen():

PHP:
1
2
3
4
5
6
7
<?php
function countToTen()
{
    global $testclass, $someArray;
...
}
?>

  • Struikrover
  • Registratie: Juni 2005
  • Nu online
spleethoven schreef op woensdag 27 juli 2011 @ 11:38:
Constructors worden op deze manier geschreven in PHP:

PHP:
1
2
3
function __construct() {
       print "constructor\n";
   }
zoals hieronder staat: op mijn manier kan het ook. Bovendien ben ik dit gewend vanuit Java, en staat het mooier :).
hostname schreef op woensdag 27 juli 2011 @ 11:41:
Lees je eens in over de scope van objecten. Je maakt $testclass buiten de functie aan, en dus is deze niet beschikbaar in de functie countToTen()


[...]

De manier in de TS werkt ook (ja; PHP heeft 2 manieren om constructors te noemen...)
Held _/-\o_ . Ik had geen flauw idee dat PHP standaard een nieuwe var aanmaakt in een lagere scope, ookal bestaat die variable globaal al.

Is dit dan good practice, of kan het beter op een andere manier? Ik ben nml. de 'global' keyword echt nog nooit tegen gekomen
PHP:
1
2
3
4
5
6
7
8
9
10
    require_once("classes/testClass.php");

    $testclass = new testClass();

    $someArray = array();
    
    function countToTen(){
        global $someArray, $testclass;
        $someArray = $testclass -> doCount();
    }


EDIT: @hierboven: dank je voor de redundantie :). Ik snap helemaal waarom mijn code het niet deed. Nogmaals mijn vraag: is bovenstaande code ook correct en goed gebruik?

[ Voor 6% gewijzigd door Struikrover op 27-07-2011 12:11 ]


  • dygnus
  • Registratie: Mei 2008
  • Laatst online: 06-08 15:41
Ik zou je functie persoonlijk zo schrijven (al heb ik geen idee wat je er mee wilt):

PHP:
1
2
3
4
5
6
7
8
9
<?php
function countToTen ()
{
    $testclass = new testClass();
    return $testclass->doCount();
}

print_r(countToTen());
?>

  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

Globals gebruiken is nogal onnodig in dit geval. Als je vóór je functie-aanroep nog iets met $testclass wil doen, geef je die gewoon als parameter mee aan je functie. Dus:

PHP:
1
2
3
4
5
6
7
8
9
10
11
$testclass = new testClass();

$testclass->Foo = "bar";
$testclass->Baz();

$someArray = countToTen($testclass);

countToTen($forthisclass)
{
  return $forthisclass->doCount();
}


Echter, als countToTen alleen een functie voor die klasse is, waarom zit 'ie dan niet ín die klasse?

[ Voor 12% gewijzigd door CodeCaster op 27-07-2011 12:19 ]

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...


  • Struikrover
  • Registratie: Juni 2005
  • Nu online
dygnus schreef op woensdag 27 juli 2011 @ 12:12:
Ik zou je functie persoonlijk zo schrijven (al heb ik geen idee wat je er mee wilt):

PHP:
1
2
3
4
5
6
7
8
9
<?php
function countToTen ()
{
    $testclass = new testClass();
    return $testclass->doCount();
}

echo countToTen();
?>
Het is de bedoeling dat er meerdere functies als 'countToTen' zijn, die corresponderen met verschillende keuzes die er op een pagina gemaakt kunnen worden. Daarom wil ik de class globaal aanroepen, en afhankelijk van wat er bijvoorbeeld in de $_SESSION of $_POST staat verschillende functies aanroepen vanuit een PHP block in de body, zoals 'countToTen' of 'maakIetsAndersMoois'.

De voornaamste reden om dat zo te doen is om mijn php code overzichtelijk te houden. Dan zou de pagina er zo uit komen te zien:

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
31
32
33
34
35
36
37
38
39
40
<?php
    require_once("classes/objectClass.php");

    $object = new objectClass();
    
    function doeIets(){
        //print een tabel met data uit $object -> tabelData
    }

    function doeIetsAnders(){
        //maakt een overzicht van afbeeldingen met data uit $object -> imageData
    }

    function doeNogIetsAnders(){
        //biedt mogelijkheid een bestand te uploaden
    }
?>

<!DOCTYPE html>
<html lang="nl">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
        <title>Testfile</title>

    </head>
    
    <body>
        <?php
            if(isset($_POST['table'])){
                doeIets();
            }
            else if(isset($_POST['images'])){
                doeIetsAnders();
            }
            else if(isset($_POST['new'])){
                doeNogIetsAnders();
            }
        ?>
    </body>
</html

  • Struikrover
  • Registratie: Juni 2005
  • Nu online
CodeCaster schreef op woensdag 27 juli 2011 @ 12:18:
Globals gebruiken is nogal onnodig in dit geval. Als je vóór je functie-aanroep nog iets met $testclass wil doen, geef je die gewoon als parameter mee aan je functie. Dus:

PHP:
1
2
3
4
5
6
7
8
9
10
11
$testclass = new testClass();

$testclass->Foo = "bar";
$testclass->Baz();

$someArray = countToTen($testclass);

countToTen($forthisclass)
{
  return $forthisclass->doCount();
}


Echter, als countToTen alleen een functie voor die klasse is, waarom zit 'ie dan niet ín die klasse?
Dat lijkt ook op een goede manier inderdaad. Je moet niet vergeten dat ik dit niet gewend ben omdat ik van Java af kom qua OOP, dus ik ben de goede manieren nog aan het verkennen. Thanks in ieder geval.

EDIT:
CodeCaster schreef op woensdag 27 juli 2011 @ 12:18:
Echter, als countToTen alleen een functie voor die klasse is, waarom zit 'ie dan niet ín die klasse?
Omdat ik die class graag bruikbaar wil hebben voor meerdere gelegenheden, en dus graag een scheiding wil houden tussen een algemene mogelijkheid (zoals alle afbeeldingen die voldoen aan bepaalde voorwaarden uit een folder halen en returnen in een array) en een specifieke mogelijkheid (zoals het vervolgens presenteren in een <table> van deze afbeeldingen, voor die specifieke pagina.

[ Voor 27% gewijzigd door Struikrover op 27-07-2011 12:26 ]


  • dygnus
  • Registratie: Mei 2008
  • Laatst online: 06-08 15:41
Je kan inderdaad in dat geval de class meegeven in een parameter zoals CodeCaster doet. Echter wil je soms pas in functies een class aanroepen i.v.m. variabelen die je soms niet in een eerder aangeroepen class wilt gebruiken.

Bijvoorbeeld: Je schrijft een mail-script, via de class geef je het onderwerp en geadresseerde mee. Echter moeten deze gegevens niet blijven hangen als je in loopjes werkt. Hiervoor kun je in de class een functie schrijven om deze gegevens uit het geheugen te wissen, of soms wil je de class in pas in de functie (opnieuw) aanroepen, dan weet je zeker dat deze gegevens niet blijven afhangen.

Maar voor alles wat je schrijft is het natuurlijk afwegen wat het beste werkt.
Pagina: 1