Jake
Jake

Reputation: 75

Constructor causes infinite loop

I am trying to complete this PHP challenge and I currently have this code:

<?php

/*
Challenge 2: Implement AnswerInterface and get Question to echo "4".
*/  
class Question
{
    public function __construct(AnswerInterface $answer)
    { 
        echo "What is 2 + 2?\n";
        $answer = $answer->get()->the()->answer();
        if ($answer instanceof AnswerInterface) {
            echo $answer . PHP_EOL;
        }
    }   
}   

interface AnswerInterface
{   
    public function get();
    public function the();
    public function answer();
}   

class Answer implements AnswerInterface
{   
    public function get()
    {   
        return new Answer();
    }

    public function the()
    {
        return new Answer();
    }

    public function answer()
    {
        return new Answer();
    }

    public function __toString()
    {
        return '4';
    }
}

$answer = new Answer;
$question = new Question($answer);

When I run the code like this, it gives me the error:

Fatal error: Allowed memory size of 134217728 bytes exhausted

I can fix the error by inserting the following into the code:

public function __construct() {}

I don't fully understand how this works... I would like to understand what is going on here. Any help with explaining how this works is greatly appreciated.

Upvotes: 1

Views: 730

Answers (2)

jh1711
jh1711

Reputation: 2338

Before PHP had __construct, you would create a constructor, by naming a method the same name as the class. This is still supported, but deprecated in PHP 7. This means if your Answer class does not have a modern constructor (__construct), the answer method will be called as a constructor. Since it returns a new Answer, the constructor will be called again on the new object, and again, and again. You have an infinite recursion, that throws an error once the memory is exhausted.

I can only guess what the reason for this exercise is. But you can also just return $this in get, the and answer. That is what you normally do, if you want your classes to support 'chaining'. Of course in the real world, the methods would also do something else.

Upvotes: 6

Max Naumenko
Max Naumenko

Reputation: 69

Basically you have correct way of thinking, but the problem is you don't need to create new instance in all methods, what you need is just return current instance of object, because you already created object Answer and pass it to the Question object, so correct code should looks something like this:

class Answer implements AnswerInterface
{

public function get()
{
    return $this;
}

public function the()
{
    return $this;
}

public function answer()
{
    return $this;
}

public function __toString()
    {
        return "4";
    }
}

You also may want to read about $this keyword here PHP: The Basics

Also method answer() will be considered as constructor method for class Answer(no matter is it lowercase or uppercase) if you don't use namespace after PHP 5.3.3(or it will be considered as constructor anyway if you have PHP 5.3.0-5.3.2). So in your case you also have infinite loop while trying to call new Answer() in implemented methods.

Upvotes: 2

Related Questions