OOP - Using Extends

Hello All,

Have some more questions please. Having a problem with extends. I want to output a box with a heading in my first class (works fine)

But then in my second class want to use ‘extends’ to output a heading (from the class CssBox) AND some lipsum text below that. Here’s my code:



//* New Class which contains a box and a heading
Class CssBox {

 protected $boxstyle; 
 protected $heading; //So should pass over using extends

  function __construct($boxstyle) { 
    $this->boxstyle = $boxstyle; 
  }
  
  function theHeading($heading) { 
    $this->heading = $heading; 
  }
  
  function displayWholeBox() {
    return "<div class='".$this->boxstyle."'>".$this->heading."</div>";
  }
  
  

}

//* New Class using extends to grab that heading from the parent class (BUT NOT the box style) above class using extends and plonk some lipsum text underneath
class Lipsum extends CssBox {

  private $lipsum;
  
  function theText($lipsum) {
    $this->lipsum = $lipsum;
  }
  
  function displayText() {
    return "<div class='<h1>".$this->heading."</h1>\
<p>".$this->lipsum."</p>";
  }

}

//* All outputs fine
$box1 = new CssBox("box_long");
$box1->theHeading("Hello Message"); 
echo $box1->displayWholeBox();

echo "<hr style='clear:both;margin-top:10px;' />";

//* Outputs the lipsum text but no heading and a error Missing argument 1 for CssBox::__construct()
$lipsum = new Lipsum(); 
$lipsum->theText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis porta semper nisl, non tempor felis imperdiet in. Cras feugiat, elit nec fermentum faucibus, lorem magna consequat eros, hendrerit placerat lacus ligula nec erat. Donec lacinia dolor at arcu tempor blandit. Proin mauris ipsum, porta vitae semper eu");
echo $lipsum->displayText();
?>

However i’m getting the message when I create my new instance $lipsum = new Lipsum();



Missing argument 1 for CssBox::__construct()


Now I dont see why I am getting that as when I create my instance of $lipsum = new Lipsum(); I am not asking for the constructor to be called from its parent class, just asking it to call $this->heading? So why do I have to put anything in the paranthasis here?

Also can you have a constructor in the extended class even if you have one in it’s parent class?

Thanks

Did you read my post?

$box1 and $lipsum are two different instances, they cannot share data.


$lipsum = new Lipsum("box_long");
$lipsum->theHeading("Hello Dog");
$lipsum->theText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis porta semper nisl, non tempor felis imperdiet in. Cras feugiat, elit nec fermentum faucibus, lorem magna consequat eros, hendrerit placerat lacus ligula nec erat. Donec lacinia dolor at arcu tempor blandit. Proin mauris ipsum, porta vitae semper eu");
echo $lipsum->displayText();

Thanks, OK I get the optional parameter bit now, but I still don’t get why $this->heading does not show when I call my displayText() method as surely it inherits that from the above class. I don’t think anyone has kindly explained that too well and what I need to do to solve that issue?


<?php

Class CssBox {

 protected $boxstyle; 
 protected $heading; 

  function __construct($boxstyle = '') {
    $this->boxstyle = $boxstyle; 
  }
  
  function theHeading($heading) { 
    $this->heading = $heading; 
  }
  
  function displayWholeBox() {
    return "<div class='".$this->boxstyle."'>".$this->heading."</div>";
  }

}

class Lipsum extends CssBox {

  private $lipsum;
  
  function theText($lipsum) {
    $this->lipsum = $lipsum;
  }
  
  function displayText() {
    return "<h1>".$this->heading."</h1>\
<p>".$this->lipsum."</p>";
  }

}

$box1 = new CssBox("box_long");
$box1->theHeading("Hello Dog"); 
echo $box1->displayWholeBox();

echo "<hr style='clear:both;margin-top:10px;' />";

$lipsum = new Lipsum();
$lipsum->theText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis porta semper nisl, non tempor felis imperdiet in. Cras feugiat, elit nec fermentum faucibus, lorem magna consequat eros, hendrerit placerat lacus ligula nec erat. Donec lacinia dolor at arcu tempor blandit. Proin mauris ipsum, porta vitae semper eu");
echo $lipsum->displayText();
?>

Thanks for all your help and explanations.

Chris

So in that case are you saying it is good practice to make all paraters optional like so? I can’t quite get it in my head when and where a parameter could be optional, so is it best to set them all to ($var=‘’). Maybe someone could kindly point me in the direction of a URL to explain this?

Optional parameters are there for when a function doesn’t actually need them, but they can be passed. If your construct doesn’t always need the $boxstyle value, then it makes sense to define it as optional.
However, if you have a method relies on the value (your ‘theHeading’ and ‘theText’ methods) then defining the parameter doesn’t make sense as that’s the whole point of the function.

You can make them optional in you new child class and instantiate the default parameter and pass it to the parent constructor



  function __construct($boxstyle = false) { 

    if ($boxstyle !== false) $boxstyle = 'something';
    parent::__construct($boxstyle);

  }


Thanks for that. But a couple of questions still if that’s OK:

  1. So take this made up Class I just made:

<?php

class Something {

public $boxstyle;  
public $heading; 
public $lipsum; 

  function __construct($boxstyle='') {
    $this->boxstyle = $boxstyle; 
  }
  
  function theHeading($heading='') { 
    $this->heading = $heading; 
  }
    
  function theText($lipsum='') {
    $this->lipsum = $lipsum;
  }

}

?>

So in that case are you saying it is good practice to make all paraters optional like so? I can’t quite get it in my head when and where a parameter could be optional, so is it best to set them all to ($var=‘’). Maybe someone could kindly point me in the direction of a URL to explain this?

  1. Also for some reason my $this->heading is not being outputted to the page when I echo my displayText() method, the $this->lipsum is fine, but that inherited $this->heading part is not.


<?php

Class CssBox {

 protected $boxstyle; 
 protected $heading; 

  function __construct($boxstyle='') {
    $this->boxstyle = $boxstyle; 
  }
  
  function theHeading($heading) { 
    $this->heading = $heading; 
  }
  
  function displayWholeBox() {
    return "<div class='".$this->boxstyle."'>".$this->heading."</div>";
  }

}

class Lipsum extends CssBox {

  private $lipsum;
  
  function theText($lipsum) {
    $this->lipsum = $lipsum;
  }
  
  function displayText() {
    return "<h1>".$this->heading."</h1>\
<p>".$this->lipsum."</p>";
  }

}

$box1 = new CssBox("box_long");
$box1->theHeading("Hello Dog"); 

echo "<hr style='clear:both;margin-top:10px;' />";

$lipsum = new Lipsum();
$lipsum->theText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis porta semper nisl, non tempor felis imperdiet in. Cras feugiat, elit nec fermentum faucibus, lorem magna consequat eros, hendrerit placerat lacus ligula nec erat. Donec lacinia dolor at arcu tempor blandit. Proin mauris ipsum, porta vitae semper eu");
echo $lipsum->displayText();
?>

When you extend a class, you inherit any methods from the parent class. Thus, since the lispum class does not have a constructor, the parents constructor is called.

To get around this, simply make the parameter optional:

Class CssBox {
    function __construct($boxstyle = '') { 
        $this->boxstyle = $boxstyle; 
      }

It is possible to have a constructor in the child class. You simply define it and that overloads the parent’s method. If you want to run the parent’s construct as well, you do:

class foo extends bar
{
   public function __construct($var = '')
   {
      parent::__construct($var);
      
      // Some extra stuff here...
   }
}

When extending classes, think of it more in the line of the “lipsum” class have all the properties and methods of both the Lipsum and the CssBox class… it will be one single class.
There are no need for you to first make an instance of the CssBox class and then make an instanse of the Lipsum class.

So from the Lipsum class, which extends CssBox, you have access to the “DisplayWholeBox” method, if the method is not private.

in your example:


$box1 = new CssBox("box_long");
$box1->theHeading("Hello Dog"); 

echo "<hr style='clear:both;margin-top:10px;' />";

$lipsum = new Lipsum();
$lipsum->theText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis porta semper nisl, non tempor felis imperdiet in. Cras feugiat, elit nec fermentum faucibus, lorem magna consequat eros, hendrerit placerat lacus ligula nec erat. Donec lacinia dolor at arcu tempor blandit. Proin mauris ipsum, porta vitae semper eu");
echo $lipsum->displayText();

The $box1 and the $lipsum are two distinct and different objects.
So setting the heading in $box1 doesnt let $lipsum access it.

instead, you should do something like this:


echo "<hr style='clear:both;margin-top:10px;' />";


$lipsum = new Lipsum("box_long");
$lipsum->theHeading("Hello Dog");

$lipsum->theText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis porta semper nisl, non tempor felis imperdiet in. Cras feugiat, elit nec fermentum faucibus, lorem magna consequat eros, hendrerit placerat lacus ligula nec erat. Donec lacinia dolor at arcu tempor blandit. Proin mauris ipsum, porta vitae semper eu");

echo $lipsum->displayText();

But because the “theHeading” from the CssBox is protected, you cant access it from outside any of the classes, only from within them, so the code wont work.
EDIT: my mistake… the variable “$heading” is protected, not the method “theHeading()”, so it should work…

About making values optional for a method, its really op to what the method does, and how you work with it.

Considering a div box, sometimes you might want to have a heading, sometimes you dont… in that case it would make sense to make the value optional.

With the text part of the box, well… you probably always want something within the box, so the text value should be required (not optional).

Since its you who are making the methods, its really op to you to define the rules.