Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

PHP Object-Oriented PHP Basics Building a Collection Enhancing the Collection

Jonathan Grieve
MOD
Jonathan Grieve
Treehouse Moderator 91,252 Points

PHP Error, call to member function. Lost.

Hi all, I've followed the video up to this point and managed to build the collection of recipes. Howver since then I've got a fatal error that won't go away from the render method.

Fatal error: Call to a member function getTitle() on array in C:\xampp\htdocs\treehouse\php\php-cookbook\render.php on line 27

I'm lost and out of ideas what I need to do to fix this and move on.

http://www.jonniegrieve.co.uk/jg-lab.co.uk/php-cookbook/cookbook.php

render.php
<?php

class Render {

            public function __toString() {
                   $output = "";
                   $output .= "<br />The following methods are available for " . __CLASS__ . "objects  <br />";
                   $output .= implode("<br />", get_class_methods(__CLASS__));

                return $output;
            }

            public static function listIngredients($ingredients) {
                $output = "<br />";
                foreach ($ingredients as $ing) {
                    $output .= $ing["amount"] . " " . $ing["measure"] . " " . $ing["item"];
                    $output .= "<br />";
                }
                return $output;
            }

            /*display Recipe method*/           
            public static function displayRecipes($recipe) {

                $output = "";
                $output .= "<br />---------<br />";
                $output .= $recipe->getTitle() . " by " . $recipe->getSource();
                $output .= "<br />";
                $output .= self::listIngredients($recipe->getIngredients() );
                $output .= implode(", ", $recipe->getTags());
                $output .= "<br />";
                $output .= "----Instructions----";
                $output .= "<br />";
                $output .= implode("<br />", $recipe->getInstruction() );
                $output .= "<br />";            
                $output .= "<br />";            
                $output .= $recipe->getYield();
                $output .= "<br />";                
                //$output .= $recipe->getSource();

                /*<br /> for new line when outputting to a html file.*/
                return $output;

            }


        public static function listRecipes($titles) {

           //sort the titles array;
           asort($titles);

           return implode("\n", $titles);
        }
}

?>
recipe.php
        <?php

        class Recipe {

            //These are properties of the Recipe class.  Some are arrays, some are strings.     
            private $title;
            private $ingredients = array();
            private $instructions = array();
            private $recYield;
            private $tag = array();
            private $source = "Jonathan";
            private $measurements = array(
                "tsp",
                "tbsp",
                "cup",
                "oz",
                "lb",
                "fl oz",
                "pint",
                "quart",
                "gallon",

            );

            /*getters and setters for private properties*/
            /*public function setTitle($title) {
                  $this->title = ucwords($title);
            }*/


            public function setTitle($title) {
               if(empty($title)) {
                  $this->title = null;
               } else {
                 $this->title = ucwords($title);
               }
            }

            public function getTitle() {
                  return $this->title;
            }            

            //"add" function for adding ingredients to cookbook.
            public function addIngredient($item, $amount = null, $measure = null) {


                // If there's a value of amount and it is neither a float or an integer, display a message. 
                if ($amount != null && !is_float($amount) && !is_int($amount)) {
                    exit("The amount must be a float: " . gettype($amount) . " $amount given");
                }
                // if there  is a value but not a valid measurement from measurement array display a message.
                if ($measure != null && !in_array(strtolower($measure), $this->measurements)) {
                    exit("Please enter a valid measurement: " . implode(", ", $this->measurements));
                }       
                //add ingredients as an associative array   "items" =>ucwords($item),

                $this->ingredients[] = array(
                    "item" => ucwords($item),
                    "amount" => $amount,
                    "measure" => strtolower($measure)
                );
            }

            public function getIngredients() {
                return $this->ingredients;
            }

            public function addTag($tag) {
                $this->tags[] = strtolower($tag);
            }

            public function getTags() {
                return $this->tags;
            }       

            public function addInstruction($string) {
                $this->instructions[] = $string;

            }

            public function getInstruction() {
                return $this->instructions;

            }

            public function setSource($source) {
                $this->source = ucwords($source);
            }

            public function getSource() {
                return $this->source;
            }

            public function setYield($yield) {
                $this->recYield = $yield;
            }

            public function getYield() {
                return $this->recYield;
            }           

            public function __construct($title=null) {
                return $this->setTitle($title);

            }

            public function __toString() {
                   $output = "You are calling a " . __CLASS__ . " object with the title \"";
                   $output .= $this->getTitle() . "\"";
                   $output .= "<br />It is stored in " . basename(__FILE__) . " at " . __DIR__ . ".";
                   $output .= "<br />This display is from line " . __LINE__ . " in method " . __METHOD__;
                   $output .= "<br />The following methods are available for objects of this class: <br />";
                   $output .= implode("<br />", get_class_methods(__CLASS__));

                return $output;
            }

        }
        ?>
cookbook.php
<html>
<head>
    <title>PHP: Cookbook using Object Oriented Programming</title>

    <link href="https://fonts.googleapis.com/css?family=Roboto+Slab" rel="stylesheet">
    <link href="styles.css" rel="stylesheet" type="text/css" />

</head>
<body>

    <header>
        <img class="logo" src = "logo.png" />
    </header>

    <div class="pp_head">
        <h1>PHP: Cookbook using Object Oriented Programming</h1>

        <p class="center"><a href="">Recipe List</a></p>
    </div>

    <div class = "content">
        <!-- -->

        <h1>Cookbook</h1>

        <?php

            include "recipe.php";
            include "render.php";
            include "inc/recipes.php";
            include "recipiecollection.php";

            echo "Cookbook: Recipies by Alena Holligan and Ken Alger";

            //echo Render::displayRecipe($recipe1);
            //echo Render::displayRecipe($recipe2);
            //echo Render::displayRecipe($lemon_chicken);
            //echo Render::listIngredients($ingredients);

            /***************************************
            Display Recipies as Collections Cookbook
            ***************************************/

            $cookbook = new RecipeCollection("Treehouse Recipies");

            echo $cookbook->addRecipe($lemon_chicken); 
            $cookbook->addRecipe($granola_muffins);
            $cookbook->addRecipe($belgian_waffles);
            $cookbook->addRecipe($pepper_casserole);
            $cookbook->addRecipe($lasagna);
            $cookbook->addRecipe($dried_mushroom_ragout);
            $cookbook->addRecipe($rabbit_catalan);
            $cookbook->addRecipe($grilled_salmon_with_fennel);
            $cookbook->addRecipe($pistachio_duck);
            $cookbook->addRecipe($chili_pork);
            $cookbook->addRecipe($crab_cakes);
            $cookbook->addRecipe($beef_medallions);
            $cookbook->addRecipe($silver_dollar_cakes);
            $cookbook->addRecipe($french_toast);
            $cookbook->addRecipe($corn_beef_hash);
            $cookbook->addRecipe($granola);
            $cookbook->addRecipe($spicy_omelette);
            $cookbook->addRecipe($scones);

            //var_dump($cookbook);

            //cookbook.php  - to display the titles.
            echo Render::displayRecipes($cookbook->getRecipeTitles());
        ?>


    </div>

    <footer>
        <p>PHP: Cookbook using Object Oriented Programming. From Teehouse by Jonnie Grieve Digital Media</a></p> 
    </footer>
</body>

</html>

What does $cookbook->getRecipeTitles() return?

Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,252 Points

Hi Christian,

I thought the idea was it was to print out one by each each Recipe title.?

Not sure what the idea is. I haven't done this task. But can tell me what this gives you?

var_dump($cookbook->getRecipeTitles());

Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,252 Points

This is what I tried to do earlier... some var dumps around the code to try and debug and see what I could find but could find no visible difference.

Anyway I've just don't a var dump where you suggested on my local server and it came up with this.

array(0) { } 

Which suggests to me that an array that should be being populated with Recipe titles... isn't. :-)

Right, so the recipes aren't being added properly. It's hard for me to tell as I don't have access to the code. Another thing I see is that you are sending in a variable to all of the $cookbook->addRecipe(______); calls. For example $granola_muffins and $belgian_waffles. I don't see them declared anywhere. Make sure they are, or otherwise you'd be sending in null and that may cause the array to be empty.

Are they supposed to be strings? If so, just try $cookbook->addRecipe("test"); and do the save var_dump as before and see what you get.

Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,252 Points

Hmm,. the variables are declared in another file called recipes.php which is included in cookbook.php

I've just done a var_dump on one of the recipes and got this.

            $cookbook = new RecipeCollection("Treehouse Recipies");

            echo $cookbook->addRecipe($lemon_chicken); 
            echo $cookbook->addRecipe(var_dump($lemon_chicken) ); 
#3 (8) { ["title":"Recipe":private]=> string(21) "Italian Lemon Chicken" ["ingredients":"Recipe":private]=> array(10) { [0]=> array(3) { ["item"]=> string(5) "Pasta" ["amount"]=> int(1) ["measure"]=> string(2) "lb" } [1]=> array(3) { ["item"]=> string(14) "Chicken Breast" ["amount"]=> int(2) ["measure"]=> string(2) "lb" } [2]=> array(3) { ["item"]=> string(9) "Olive Oil" ["amount"]=> float(0.5) ["measure"]=> string(3) "cup" } [3]=> array(3) { ["item"]=> string(15) "Garlic, Chopped" ["amount"]=> int(2) ["measure"]=> string(4) "tbsp" } [4]=> array(3) { ["item"]=> string(11) "Lemon Juice" ["amount"]=> float(0.25) ["measure"]=> string(3) "cup" } [5]=> array(3) { ["item"]=> string(5) "Sugar" ["amount"]=> float(0.5) ["measure"]=> string(3) "tsp" } [6]=> array(3) { ["item"]=> string(7) "Parsley" ["amount"]=> int(2) ["measure"]=> string(3) "tsp" } [7]=> array(3) { ["item"]=> string(7) "Oregano" ["amount"]=> int(2) ["measure"]=> string(3) "tsp" } [8]=> array(3) { ["item"]=> string(5) "Basil" ["amount"]=> int(1) ["measure"]=> string(4) "tbsp" } [9]=> array(3) { ["item"]=> string(25) "Parmesian Cheese To Taste" ["amount"]=> NULL ["measure"]=> string(0) "" } } ["instructions":"Recipe":private]=> array(5) { [0]=> string(42) "Cook pasta according to package directions" [1]=> string(116) "In a large skillet on medium high heat, saute garlic in olive oil for 3 minutes. Cut chicken into bite sized pieces." [2]=> string(103) "Add additional items to sauce pan and cover for 5 minutes or untill chicken is almost completely white." [3]=> string(51) "Remove lid and cook until reduced to a thick sauce." [4]=> string(47) "Serve over pasta with parmesian cheese to taste" } ["recYield":"Recipe":private]=> string(10) "6 Servings" ["tag":"Recipe":private]=> array(0) { } ["source":"Recipe":private]=> string(9) "Ken Alger" ["measurements":"Recipe":private]=> array(9) { [0]=> string(3) "tsp" [1]=> string(4) "tbsp" [2]=> string(3) "cup" [3]=> string(2) "oz" [4]=> string(2) "lb" [5]=> string(5) "fl oz" [6]=> string(4) "pint" [7]=> string(5) "quart" [8]=> string(6) "gallon" } ["tags"]=> array(1) { [0]=> string(9) "main dish" } } array(0) { } 
Fatal error: Call to a member function getTitle() on null in C:\xampp\htdocs\treehouse\php\php-cookbook\render.php on line 27

1 Answer

Hi Jonathan,

Line 27 in render.php is

$output .= $recipe->getTitle() . " by " . $recipe->getSource();

The error message says that you're calling the getTitle() method on an array. This means that $recipe is an array.

You can work your way back to where you called the displayRecipes() method to see what you passed in for an argument.

//cookbook.php  - to display the titles.
echo Render::displayRecipes($cookbook->getRecipeTitles());

You're not showing your recipeCollection class but I would guess that getRecipeTitles() is returning an array of titles.

This array is then passed into displayRecipes but that method is expecting a recipe object.

Your comment indicates that you were intending to display the titles. Your static listRecipes method does accept an array of titles.

Maybe you intended to do this?

//cookbook.php  - to display the titles.
echo Render::listRecipes($cookbook->getRecipeTitles());
Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,252 Points

Hi Jason,

Thanks for your reply :)

I did look at the files based on the error message and I confess I didn't realise I was calling the wrong method. I changed it and found the message was gone but nothing was being returned.

So I var dummped the output and it returned this .

Cookbook: Recipies by Alena Holligan and Ken Algerarray(0) { } 
Warning: asort() expects parameter 1 to be array, null given in C:\xampp\htdocs\php-cookbook\render.php on line 50

Warning: implode(): Invalid arguments passed in C:\xampp\htdocs\php-cookbook\render.php on line 52

So for some reason the array object is still not being populated with the array titles. :/

This is my recipe collection class.

recipiecollection.php
<?php   
class RecipeCollection {

  private $title;
  private $recipes = array();


    public function setTitle($title) {
            if(empty($title)) {
                $this->title = null;
            } else {
                $this->title = ucwords($title);
               }
            }

    public function getTitle() {
        return $this->title;
    }       

    public function addRecipe($recipe) {
        $this->recipies[] = $recipe;
    }

    public function getRecipies() {
        return $this->recipes;
    }

    public function __construct($title=null) {
        return $this->setTitle($title);

    }

    public function getRecipeTitles() {

          //initialise titles array
          $titles = array();

          //loop through each recipe and get only the title
          foreach($this->recipes as $recipe) {
              $titles[] = $recipe->getTitle();
          }

          //return the titles
          return $titles;
    }
}
Jonathan Grieve
Jonathan Grieve
Treehouse Moderator 91,252 Points

Phew! I did it!

I was able to get into the RecipeCollection class and slightly modify a method to get the list to display.

Only, I fixed it before I realised it and it is only now I managed to trace it. I knew I'd fixed it when the var dump spewed more results.

Eventually identified the addRecipe method had an invalid property. So

<?php
    public function addRecipe($recipe) {
        $this->recipies[] = $recipe;
    }
?>

Should have been

<?php

    public function addRecipe($recipe) {
        $this->recipies[] = $recipe;
    }
?>

Done! :)

Glad you sorted it out.