0

I want to increase my knowledge of PHP by learning about classes. I wrote the following very simple test program. It works. But I would like to know improve it. I plan on writing more complex test programs and that won't be the time to iron out smaller issues. Thanks in advance.

<?php
$length = array_key_exists('length', $_POST) ? $_POST['length'] : null;
$width = array_key_exists('width', $_POST) ? $_POST['width'] : null;

if ($length == "") $length = 0;
if ($width == "") $width = 0;
?>

<?php

class Shape {
   var $length;
   var $width;

   function setLength($Length) {
      $this -> length = $Length;
   }

   function setWidth($Width) {
      $this -> width = $Width;
   }

   function getPerimeter() {
      return 2 * ($this -> length + $this -> width);
   }

   function getArea() {
      return $this -> length * $this -> width;
   }
}

$rectangle0 = new Shape;

   $rectangle0 -> setLength("$length");
   $rectangle0 -> setWidth("$width");

?>

<p>&nbsp;</p>
<p>&nbsp;</p>

<form method=post name="form1" action="practice1.php">

<div class="row">
<label for="winnings">Enter length: &nbsp; &nbsp;</label>
<input style="font-size:12pt" type="text" id="length" name="length" value="<?php if (isset($_POST['length'])) {echo $_POST['length'];} ?>" size="15"/>
<br style="clear:left"/>

<label for="losses">Enter width: &nbsp; &nbsp;</label>
<input style="font-size:12pt" type="text" id="width" name="width" value="<?php if (isset($_POST['width'])) {echo $_POST['width'];} ?>" size="15"/>
<br style="clear:left"/>
</div>

<p>&nbsp;</p>
<p>&nbsp;</p>

<input style="font-size:12pt" type=submit name=submit value="Compute" >
<input type=hidden name=submitted value="true" >

<p>&nbsp;</p>
<p>&nbsp;</p>

<div class="row">
<label for="tax" id="tax" style="font-size:13pt">The perimeter of the rectangle is:</label>
<input style="font-size:12pt" type=text id="perimeter" name="perimeter" value="<?php echo $rectangle0 -> getPerimeter() ?>" size=10 maxlength=10></td>
<br style="clear:left"/><br />

<label for="deficiency" id="deficiency" style="font-size:13pt">The area of the rectangle is:</label>
<input style="font-size:12pt" type=text id="area" name="area" value="<?php echo $rectangle0 -> getArea() ?>" size=10 maxlength=10></td>
<br style="clear:left"/>
</div>

</form>

Edited by Nathaniel10

6
Contributors
28
Replies
152
Views
2 Years
Discussion Span
Last Post by diafol
Featured Replies
  • 1
    jkon 506   2 Years Ago

    PHP is a multi-paradigm programming language . Even its object oriented face has many moods that sometimes look like Java sometimes like C++ and other times like a bizarre mix. I start with those phrases to emphases that there is no “correct” way of OOP in PHP (except you are … Read More

  • I totally agree with jkon, OOP is OOP in your style. But there are a few things you should also know which will help in your life of programming. This include errors you made in both PHP and HTML. (NOTE: reference XHTML, PHP5 and **My Personal Interests**). 1. The inclusion … Read More

  • 1
    jkon 506   2 Years Ago

    Nathanial as I wrote there are many approaches. You say that some tutorials you have read do it that way. If it suits you then there is no problem about it. Here is an example of your class as the “best OOP practices” I have decided to follow. ( I … Read More

  • 1
    diafol 3,720   2 Years Ago

    To my mind the *shape* class should be *abstract* as it should never be made into a "real life object". You can of course get into a number of levels of subclassing, e.g. circle may be an extension of an ellipse as ellipse is an extension of a shape. You … Read More

  • 1

    > For example, the constant pi is not needed in any shape with only straight lines That's debatable: perhaps in the future you'll want to extend your class with a method to determine the smallest circle your shape is in ;) An abstract class is like a blueprint (similar to … Read More

0

I'm not sure what are you asking of us here? To teach you PHP OOP?

I want to increase my knowledge of PHP by learning about classes.

I would recommend going through the large number of tutorials and information that is already online about PHP classes.

1

PHP is a multi-paradigm programming language . Even its object oriented face has many moods that sometimes look like Java sometimes like C++ and other times like a bizarre mix. I start with those phrases to emphases that there is no “correct” way of OOP in PHP (except you are doing something awfully wrong). There are many ways and what will you choose depends of what programmer are you and what want to be.

Having said that , here are some thoughts on your code, based in the way I chosen for OOP with PHP. Properties must (again here the “must” refers to the way I chosen) declare their scope. There is no reason to use the var keyword. Is it public ? Is it protected? Is it private ? . The same goes with static properties as well. Of course methods should have a scope , logically in your class length is private and you have public methods getLength() and setLength($length) (why you capitalize in setLength($Length) ? ) .

You use a space arround -> ($this -> width) for example . In my point of view this makes the code hard to read. When you use the setters of the class you pass the variable using “” ( eg. setLength("$length") ) why ? . As a test you are starting with OOP with PHP , think about separating class from html code as a next step.

2

I totally agree with jkon, OOP is OOP in your style. But there are a few things you should also know which will help in your life of programming. This include errors you made in both PHP and HTML. (NOTE: reference XHTML, PHP5 and My Personal Interests).

  1. The inclusion of the class in the same file as other php and html codes does not encourage the idea of OOP. Usually create a file to contain only the Class or group of classes, then you include them on the page they will be needed. You can also use spl_autoload to load your classes without having to include them one by one.

  2. In your if statement, the codes should have been in parenthesis which shows that if the condition is correct run this specific codes.

  3. HTML attributes should have their values placed in double quotation marks. You did some right and left a massive number of them. I recommend you to do that if you want your projects to be of the W3C standards.

  4. You could have made your codes shorter and more readable by making the width and length arguments or parameters of the methods of the class. (Personal Preference).

  5. Indenting of codes is a good practice if you want to become an elite programmer. Always indent your codes to produce neat work.

  6. I don't know how you understand labels and their ids. The label id must be equal to the input field's id. (The field you want to address the label to). The purpose is that, when the label is click it automatically makes its input field selected or let me say active.

This is a simplified or more confusing version of your codes which really depends on you.

<?php
   $length = array_key_exists('length', $_POST) ? $_POST['length'] : null;
   $width = array_key_exists('width', $_POST) ? $_POST['width'] : null;

   if ($length == "") {$length = 0;}
   if ($width == "") {$width = 0;}

   class Shape {
      private $perimeter,
               $area;

      public function getPerimeter($length, $width) {
         $this->perimeter = 2 * ($length + $width);
         return $this->perimeter;
      }

      public function getArea($length, $width) {
         $this->area = $length * $width;
         return $this->area;
      }
   }

      $rectangle0 = new Shape;
   ?>

   <form name="form1" action="" method="post">
      <div class="row">
         <label for="length">Enter length: &nbsp; &nbsp;</label>
         <input style="font-size:12pt" type="text" id="length" name="length" value="<?php if (isset($_POST['length'])) {echo $_POST['length'];} ?>" size="15"/>

         <br style="clear:left"/><br>

         <label for="width">Enter width: &nbsp; &nbsp;</label>
         <input style="font-size:12pt" type="text" id="width" name="width" value="<?php if (isset($_POST['width'])) {echo $_POST['width'];} ?>" size="15"/>

         <br style="clear:left"/>
      </div>

         <p>&nbsp;</p>
         <p>&nbsp;</p>

         <input style="font-size:12pt" type="submit" name="submit" value="Compute" >
         <input type="hidden" name="submitted" value="true" >

         <p>&nbsp;</p>
         <p>&nbsp;</p>

      <div class="row">
         <label for="perimeter" style="font-size:13pt">The perimeter of the rectangle is:</label>
         <input style="font-size:12pt" type=text id="perimeter" name="perimeter" value="<?php echo $rectangle0->getPerimeter($length, $width) ?>" size=10 maxlength=10></td>

         <br style="clear:left"/><br />

         <label for="area" style="font-size:13pt">The area of the rectangle is:</label>
         <input style="font-size:12pt" type=text id="area" name="area" value="<?php echo $rectangle0->getArea($length, $width) ?>" size=10 maxlength=10></td>

         <br style="clear:left"/>
      </div>
   </form>

Hope it went well.

Edited by Gideon_1

0

Thanks very much for your replies.

@pixel,

I am asking the forum to help me teach myself PHP OOP. In so doing, others will also be helped in teaching themselves PHP OOP.

@Jkon,

Your comments are very enlightening. I first learned about classes and OOP in C++. The book I used and the examples and tutorials I followed did not at all give the impression that there a lot of developer/programmer 'discretion' in OOP. There seemed to be an emphasis on best practices to which everyone was expected to adhere.

I plan to explore visibility issues later when programs are sufficeintly complex for visibility to matter.

I removed the keyword var and received an error. A function was expected rather than a variable. Restoring var removed the errror. I am running PHP 5.5.24 on XAMPP 5.6.8.

I capitalize in the function name because I follow the camel hump convention. Many tutorials followed this convention, while others used the underscore convention. I capitalized the variable in the setter functions because that is what the example I followed did. I used the double quotation marks on the fucntion argument for the same reason. I put spaces around the arrow operator because I found it easier for me to read.

One of the reasons I wanted to learn OOP in PHP rather than continue with C++ was the ease of integrating it with HTML. I have been using PHP with HTML for projects involving databases (MySQL) and extensive computations. I have seen CodeAcademy consisently combine PHP OOP with HTML in its examples.

@Gideon,

Thanks very much for your helpful comments.

1)
I saw that practice in several tutorials. I plan to follow it when I am developing longer, more complex programs.

2)
Many tutorials indicated that when there is only one statement after the if condition, no brace brackets are needed.

3)
You are right.

4)
I see the difference in those lines. I don't think I know enough about PHP to appreciate how your code for those lines is shorter amd more readable.

5)
Yes. Coding is not my profession. I am still training myself to read more left to right as indentation requires. My natural and strong inclination is to read code up and down. If that makes sense to an established programmer. My brain sees the screen like a grid. It expects the same or similar 'code structure' in the same column. I have been trying to indent 2 spaces as a happy medium.

6)
I cut and pasted most of the HTML code from another project. I forgot to change the id's to this project's. I was eager to write code that worked as intended and overlooked those details.

1

Nathanial as I wrote there are many approaches. You say that some tutorials you have read do it that way. If it suits you then there is no problem about it. Here is an example of your class as the “best OOP practices” I have decided to follow. ( I changed the name of the class from Shape to Rectangle because this is what you are talking about). Notice that I added a “business” rule that there can't be a Rectangle without a length and a width , so to instantiate a Rectangle you must give those in the constructor. The object has also getters and setters. Maybe there is another “business” rule that you can't modify the length and the width of a Rectangle , if so setters shouldn't be public (also if this is the case the area and perimeter could be private properties calculated at the construction of the object). But I will stick to what we know and give you an example. Also as I understand width and length should be only numbers , if so you could verify it also inside object in its setters (and maybe through an exception if aren't) .

Lets suppose that the file you provided is RectanglePractice.php and is under public_html folder. I created a folder named src in the same level as public_html folder is in order to save there our source files. I saved the class in its own file src/Rectangle.php

<?php
/**
 * A Rectangle object . Notice that logically there are comments when needed 
 * at least in public methods. 
 */
class Rectangle
{
  private $width;
  private $length;

  /**
   * The rectangle object contstructor. A rectangle object can be constructed 
   * only with width and length , this is a "business" rule. 
   * @param number $width
   * @param number $length
   */
  public function __construct($width,$length)
  {
    $this->setWidth($width);
    $this->setLength($length);
  }


  /**
   * Sets the width of the rectangle
   * @param number $width
   */
  public function setWidth($width)
  {
    $this->width = $width;
  }

  /**
   * Sets the length of the rectangle
   * @param number $length
   */
  public function setLength($length)
  {
    $this->length = $length;
  }

  /**
   * Return the width of the rectangle
   * @return number
   */  
  public function getWidth()
  {
    return $this->width;
  }

  /**
   * Return the length of the rectangle
   * @return number
   */
  public function getLength()
  {
    return $this->length;
  }


  /**
   * Returns the perimeter of the rectangle 
   * @return number
   */
  public function getPerimeter()
  {
    return ( $this->getWidth() + $this->getLength() ) * 2;
  }

  /**
   * Returns the surface area of the rectangle 
   * @return number
   */
  public function getArea()
  {
    return $this->getWidth() * $this->getLength();
  }
}
?>

Now it is time for the logic I will call this class RectangleController (of course this is not a full MVC example , just how to separate code). I will save it in src/RectangleController.php

<?php 
 /**
  * This class is responsible of geting input use what ever other class needed
  * for to generate parts of the view. 
  */
 class RectangleController
 {

    /**
     * The active rectangle object if have been constructed
     * @var Rectangle
     */
    private $rectangle;    


    /**
     * An error message if the input values don't pass our "business" rules 
     * e.g. if width or heigth aren't numeric. This could also be done 
     * AND cliend side (even though we should check it server side as well) 
     * @var string
     */
    private $errorMessage = "";


    /**
     * This is just an example , in more complex projects I believe that 
     * propably you will use a framework that doesn't pass the global $_POST
     * directly
     */
    public function __construct()
    {
      // If there is a post with width and length 
      if(  isset($_POST["width"]) && isset($_POST["length"]))
      {
         // if width and length are numeric 
         if(is_numeric($_POST["width"]) && is_numeric($_POST["length"]) )
         {
           $this->rectangle = new Rectangle($_POST["width"], $_POST["length"]);
         }
         // if not , have an error message
         else 
         {
           $this->errorMessage = "Please provide numeric variable for both 
           width and length";
         }
      }
    }

    public function getWidthValue()
    {
      return isset($this->rectangle) ? $this->rectangle->getWidth() : ""; 
    }

    public function getLengthValue()
    {
      return isset($this->rectangle) ? $this->rectangle->getLength() : ""; 
    }

    public function getPerimeterValue()
    {
      return isset($this->rectangle) ? $this->rectangle->getPerimeter() : "";
    }

    public function getAreaValue()
    {
      return isset($this->rectangle) ? $this->rectangle->getArea() : "";
    }

    public function getErrorMessage()
    {
      return $this->errorMessage; 
    }
 }
?>

And now is time for the RectanglePractice.php

<?php 
/**
 * Here we will have the view
 */
class RectanglePractice
{
  /**
   * We will require once the files that we will use. Propably in more 
   * complex projects should be an autoloader with spl_autoload_register
   * or your framework will do it for you. 
   */
  public function __construct()
  {
     require_once("../src/Rectangle.php"); 
     require_once("../src/RectangleController.php"); 
     $c = new RectangleController(); 
     header('Content-Type: text/html; charset=utf-8');
?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
    <head>
        <!-- Here you will have meta tags scripts css and more -->
    </head>
    <body>
        <form method="post" name="form1" action="RectanglePractice.php" >
            <div class="errorMessage">
                <?=$c->getErrorMessage()?>
            </div>
            <br/>
            <div>
                <span>
                    Enter width *:
                </span>
                <input type="text" name="width" value="<?=$c->getWidthValue()?>" />
            </div>
            <div>
                <span>
                    Enter length *:
                </span>
                <input type="text" name="length" value="<?=$c->getLengthValue()?>" />
            </div>
            <br/>
                <input type="submit" value="Compute" >
            <br/>
            <div>
                <span>
                    The perimeter of the rectangle is:
                </span>
                <var><?=$c->getPerimeterValue()?></var>
            </div>
            <div>
                <span>
                    The area of the rectangle is:
                </span>
                <var><?=$c->getAreaValue()?></var>
            </div>                       
        </form>
    </body>
</html>     
<?php
  }
}

$rectanglePractice = new RectanglePractice(); 
?>
0

Thanks very much for the detailed reply, Jkon. Though I understand the logic of the multi-file program, the mechanics of the RectangleController file are beyond me at this time.

I used many of your suggestions in my next practice iteration. I learned something! If one does not specify the visibility of a property, then one must identify it as a property by using the keyword 'var'. The 'var' keyword is optional if one precedes a property with 'private', 'public', or 'protected'.

I tried to learn about inheritance. I am having a serious problem. When I include the function call lines of the parent class, (currently commented out), I get an error saying that there is an unexpected scope resolution operator. I am lost. Please help. Here is the current PHP code.

    <?php
    $length = array_key_exists('length', $_POST) ? $_POST['length'] : null;
    $width = array_key_exists('width', $_POST) ? $_POST['width'] : null;
    $height = array_key_exists('height', $_POST) ? $_POST['height'] : null;

    $x_radius = array_key_exists('x_radius', $_POST) ? $_POST['x_radius'] : null;
    $y_radius = array_key_exists('y_radius', $_POST) ? $_POST['y_radius'] : null;
    $z_radius = array_key_exists('z_radius', $_POST) ? $_POST['z_radius'] : null;

    if ($length == "") {$length = 0;}
    if ($width == "") {$width = 0;}
    if ($height == "") {$height = 0;}

    if ($x_radius == "") {$x_radius = 0;}
    if ($y_radius == "") {$y_radius = 0;}
    if ($z_radius == "") {$z_radius = 0;}

    ?>

    <?php

    class Shape {
       const density = '2.5';

    //   function getWeight() {
    //      return $this -> Shape::density * getVolume();
    //   }

    }

       class Hexahedron extends Shape {
          private $length;
          private $width;
          private $height;

          public function __construct($length, $width, $height) {
             $this -> setLength($length);
             $this -> setWidth($width);
             $this -> setHeight($height);

          public function setLength($length) {
             $this -> length = $length;
          }

          public function setWidth($width) {
             $this -> width = $width;
          }

          public function setHeight($height) {
             $this -> height = $height;
          }

          public public function getPerimeter() {
             return 4 * ($this -> length + $this -> width + $this -> height);
          }

          public function getArea() {
             return 2 * ($this -> length * $this -> width + $this -> length * $this -> height + $this -> height * $this -> width);
          }

          public function getVolume() {
             return $this -> length * $this -> width * $this -> height;
          }
       }

       class Ellipsoid extends Shape {
          const pi = '3.14159265359';
          private $x_radius;
          private $y_radius;
          private $z_radius;

          public function __construct($x_radius, $y_radius, $z_radius) {
             $this -> setX_radius($x_radius);
             $this -> setY_radius($y_radius);
             $this -> setZ_radius($z_radius);

          public function setX_radius($x_radius) {
             $this -> x_radius = $x_radius;
          }

          public function setY_radius($y_radius) {
             $this -> y_radius = $y_radius;
          }

          public function setZ_radius($z_radius) {
             $this -> z_radius = $z_radius;
          }

          public function getCircumference() {
             return 2 / pow(2, 0.5) * self::pi * (pow(($this -> x_radius * $this -> x_radius + $this -> y_radius * $this -> y_radius), 0.5) +
                                                  pow(($this -> x_radius * $this -> x_radius + $this -> z_radius * $this -> z_radius), 0.5) +
                                                  pow(($this -> y_radius * $this -> y_radius + $this -> z_radius * $this -> z_radius), 0.5));
         }

          public function getArea() {
             return 4 * self::pi * pow((pow(($this -> x_radius * $this -> y_radius), 1.6) + pow(($this -> x_radius * $this -> z_radius), 1.6) + pow(($this -> z_radius * $this -> y_radius), 1.6))/3, 0.625);
          }

          public function getVolume() {
             return 4/3 * self::pi * $this -> x_radius * $this -> y_radius * $this -> z_radius;
          }
       }


    $rectangle0 = new Hexahedron;

       $rectangle0 -> setLength("$length");
       $rectangle0 -> setWidth("$width");
       $rectangle0 -> setHeight("$height");

    $sphere1 = new Ellipsoid;

       $sphere1 -> setX_radius("$x_radius");
       $sphere1 -> setY_radius("$y_radius");
       $sphere1 -> setZ_radius("$z_radius");

    ?>

My goal in this inheritance practice program is to access the constant density from the parent class multiply it by the volume of an object determined in the child class to determine its weight.

Edited by Nathaniel10

0

This is an addendum to my post earlier today.

1)
There are closing brace brackets missing from the two constructors, lines 40 and 76.

2)
There is an extra 'public' on line 53.

3)
Lines 105 and 111 should be $rectangle0 = new Hexahedron($length, $width, $height); and $sphere1 = new Ellipsoid($x_radius, $y_radius, $z_radius);, respectively.

0

OK. After some experimentation, the following code for inheritance works.

class Shape {
   const density = '2.5';

   public function getWeight() {
      return self::density * $this -> getVolume();
   }
}

[snip]

$rectangle0 = new Hexahedron($length, $width, $height);

   $rectangle0 -> setLength("$length");
   $rectangle0 -> setWidth("$width");
   $rectangle0 -> setHeight("$height");
?>

<?php echo $rectangle0 -> getWeight() ?>

However, I am not clear as to why the code works. I understand that the child class Hexahedron is inheriting the properties (density) and methods (getWeight()) of the parent class Shape. I don't understand how the parent class (Shape) is accessing the getVolume() function from the child class (Hexahedron). Is it because the function is public? Is it possible for inheritance to "go backwards" from child to parent?

As I am writing this I am still experimenting. I made the getVolume() function private. I received an error message: Fatal error: Call to private method Hexahedron::getVolume() from context 'Shape' in C:\Local\phpoop\practice2.php on line 28. So I guess I answered my own question. Parent classes can access public properties and methods from child classes. I hope someone much more knowledgeable than me can confirm this for me.

Another experiment. I made the getWeight() function in the parent class, Shape, private. I received the following error message: Fatal error: Call to private method Shape::getWeight() from context '' in C:\Local\phpoop\practice2.php on line 126. So. Does this mean that child classes cannot inherit or access private properties and methods from parent classes? Again, I hope someone much more knowledgeable than me can confirm this.

Thanks to those who have replied to this thread and thanks in advance to those who will reply.

1

To my mind the shape class should be abstract as it should never be made into a "real life object".
You can of course get into a number of levels of subclassing, e.g. circle may be an extension of an ellipse as ellipse is an extension of a shape.
You could have square, rhombus, rectangles special parallelograms and parallelogram, trapezium as special cases of quadrilaterals as extensions of shape.
However, you may find a sneaky way of having just one class for all 4 sided shapes, where you'd input an array of known sides and an array of known angles. But then you have to think of consistency with regard to the 'constructor' (if you use one) you provide to the user.

So you could end up with...

abstract class shape
class quadrilateral extends shape
class parallelogram extends quadrilateral
class square extends parallelogram

or just

abstract class shape
class quadrilateral extends shape

or the "flatter" version

abstract class shape
class rhombus extends shape
class parallelogram extends shape
class square extends shape

THere are a number of approaches you could use, but aim for consistency.

0

@diafol,

Thank you for your reply. I did some brief research on abstract classes. I agree with you. The way I have made this practice example evolve, the 'Shape' class has the characteristics of an asbtract class.

I did not get a good feel for why a class should be made abstract. What are the benefits to a program from making a class abstract? Only one of the six tutorials I read specifically addressed this issue. It said that preventing instantiation in and grouping all common properties and methods into the abstract class improves organization and functionality of the entire program. It is most beneficial in large complex programs.

For my example, I can see how forcing the instantiation of particular geometric shapes to occur in child classes specific to those shapes makes the organization of the program clearer. It allows the distribution of properties and methods unique to certain shapes to be incuded in only those child classes. For example, the constant pi is not needed in any shape with only straight lines, so it can be put in the Ellipsoid class and omitted from the Hexahedron class.

The tutorials I read also mentioned abstract methods but did not explain what they were or how they are used, at least in a way that I could understand. What are abstract methods and how are they used? Is the getWeigth() function in Shape a candidate for an abstract method?

Thanks in advance.

1

For example, the constant pi is not needed in any shape with only straight lines

That's debatable: perhaps in the future you'll want to extend your class with a method to determine the smallest circle your shape is in ;)

An abstract class is like a blueprint (similar to an interface) where if you want to use a certain method, you have to implement your own. It's to force a developer extending the class to think about what is needed.

1

The shape class in your later example is abstract , not only because a shape in real word is actually abstract but also because in your getWeight() method of it you use a another method getVolume() that you don't define. That means that this can't stand alone and need to be extended by a class that has a method getVolume(). That every final ancestor of shape should have a getVolume() method means that you should declare this method also as abstract in the shape class (you don't want objects that are shape to be instantiated if have no getVolume() method. In that way you create one more logical rule. Notice that you are talking about classes that are in inherits from the shape abstract class. If you decide that you need a rule for objects that are not in the same inheritance stack then we are talking about an interface. Closing , I noticed that you said more than one time that something is beyond you at this point, if so then it is a great bell to check it in real life and understand it.

1

OK, I may need help from better-equiped OOPers, but here's my take:

An abstract class can have abstract or "regular" methods. The abstract methods are just stated - there's no info included in them - they are there (as pritaeas points out) in order to ensure that the child ("concrete") classes have versions of these methods.

The regular methods of an abstract class can be used "as is" - that is, they are inherited by the child classes. However, they can be over-ridden by declaring a regular method with the same name within the child class.

Example (part of Shape):

abstract class Shape
{
    private $sides;

    abstract protected function get_area();

    protected get_sides()
    {
        return $this->sides;
    }
}

The above shows an abstract method 'get_area', so any classes extending Shape will have to provide their own version of it. Obviously it doesn't make sense to have an inheritable method like this as each specific shape would have very different formulae for working out the area. So, we make it abstract.

The 'get_sides' method is just a normal method that could in theory be applied to any shape, so there is no reason to make it abstract where every child class would have to create its own identical 'get_sides' method. We just inherit and use.

class Square extends Shape
{
    private $sides = 4;

    public function get_area()
    {
        return $this->width * $this->width;
    }

}

$dim = 20;
$sq = new Square();
$sq->dim($dim);  //just a method to add dimension width - not shown in class

echo 'The area for a square of side ' . $dim . ' is ' $sq->get_area() . '.';
echo '<br />';
echo 'A square has ' . $sq->get_sides() . ' sides.';

I admit this is a bit of a lame example. OK - one more thing - make abstract class methods protected so you can access them from child concrete classes. Child class visibility much be equal to, or looser than, the abstract equivalent.

0

Thank you for the very informative replies.

I am getting that abstract classes need to contain all the common elements of all the child classes. Abstract methods are methods that are declared (given a name) but not defined (have no body or return statement), meaning they don't actually do anything. I did an experiment. I found that if an abstract method is declared in an abstract parent class, it must be defined in the child class or a fatal error results. To resolve the error, the (concrete) child class must either be made abstract as well or the abstract method inherited from the abstract parent must be defined, i.e. given something to do.

I take from this that whatever is contained in an abstract parent class must be repeated and defined in every (concrete) child class. I presume that this is what Pritaeas means by the abstract class is like a blueprint and what Jkon means when he said that if every ancestor has a getVolume() method, then it should be declared in the abstract parent class.

I did some research on the Model-View-Controller concept. It is very new to me. I first learned PHP from a book written by Larry Ullman. The focus was on using PHP with MySQL. Multiple files were used for headers, footers, and connecting to and accessing the database. The MVC concept was completely absent. I am surprised I am hearing of this only in 2015 as it was first developed and proposed in 1979. TUTSPLUS.COM described MVC as the Model being data, the View being the presentation of that data, and the Controller calling and coordinating the resources needed to perform the user's actions. CodingHorror.com applied MVC to the web page explaining that the Model = HTML, the View = CSS, and the Controller = the web browser. I am going to read more about MVC and try to apply it to my practive program.

@Jkon,

I studied your code for the src/RectangleController.php file in your reply above. My impression, arrived at slowly, is that it is a form validation program. It validates the data posted by the form before that data is passed to the src/Rectangle.php file for processing. Is that correct?

1

Almost ;) . As you seen there is a view template class RectanglePractice that has no real logic inside it (but this is what in this example runs first from a web call). All it does is instantiating the RectangleController object and use it to output various things. I wouldn't describe this example as fully MVC since this wasn't my intention. The point was OOP with PHP (as you seen even the “template” is part of the view template class without any logic in it). All the rendering logic , (validation + instantiating and using the Rectangle object) is done in a class (RectangleController) that its file is not in public_html folder.

I see many times people having their PHP code (with logic) mixed with html and I really can't understand how they maintain it or why they think that this hasn't a bigger cost than gain. But of course as I said PHP is multi-paradigm and there are also many OOP flavors , it is up to you to understand those (or some of those) and decide what is more clean , logic and efficient for you.

0

I found and reviewed several examples of MVC but really only one was sufficiently clear and simple for me to reasonably understand. I played around with it to see if I could re-create things. I also consolidated it into one file.

class Model {
  function __construct() { }

  function names() {
    return $names = array("John", "Paul", "George", "Ringo", "Lennon", "McCartney", "Harrison", "Starr");
  }
}

class View {
  function __construct() {}

  function viewNames($names) {
    echo "<table><th>The Beatles</th>";
    for ($i = 0; $i < 4; $i++) {
       echo "<tr><td>".$names[$i]."</td><td>".$names[$i+4]."</td></tr>";
    }
  echo "</table>";
  }
}

class Controller {
  private $p;

  function __construct() {
    $this -> p = new Model();
  }
  function loadNames() {
    $v = new View();
    $v -> viewNames($this -> p -> names());
  }
}

$cp = new Controller();
$cp -> loadNames();

I have a decent understanding of the Model and View classes. The Model class processes data, in this case given in the array. The View class formats inputs and outputs, in this case only output.

The Controller class is less intuitive to me. It seems an instance of the Model class is being created in the Controller class. I suppose it is to be able to access the data in the Model class. Then the function in the Controller class creates an instance of the View class. I supose to be able to transfer the data it accessed from the Model class to the View class.

The last two lines create an instance of the Controller class and essentially executes the program by calling the loadNames() function.

I do not understand the MVC concept well enough yet to apply it to my Shape example. For example, I don't know how to implement an input form in the View class. I have not seen any examples of that. It will take considerable experimenting to get it close to right. Can anyone help with that?

1

I'll just make one observation with regard to the controller. The 'model' should be 'blind', that is it should function regardless of the context it finds itself in, from the point of view of what calls it and where that data needs to go (input and output). The controller is more like the glue I suppose, which calls for model data and passes it on to the view. Some frameworks (I have to be careful how I define that - but CodeIgniter and their ilk), tend to blur the line between controller and model, so much so that you could shove everything into the controller and forget the model. This is very bad as it leads to code duplication and nightmares with regard to code maintenace. The controller calls the various models passing relevant input and receives the output, which may or may not require some additional processing before being passed on to a view.

The model should not interact directly with a view. The view should only contain rudimentary code, like echo, loops and conditionals - very little else.
A typical MVC will have routing to a controller, and usually to a method (action) - sometimes with parameters. That method should specify the model(s) to use to get the data and the view(s) in order to display the data.

Getting late. If nobody else gives you an example, perhaps I give it a bash, but it may be a little while.

0

After some more research, I found a good example of implementing an input form in MVC. I was able to successfully modify the "The Beatles" example from yesterday to include an input form. It is below. The code isn't pretty but it works.

class Model {
  public $names;

  function __construct() { }

  function names() {
    return $names = array("Johnny", "Paul", "George", "Ringo");
  }

  function updateNames($name0, $name1, $name2, $name3) {
    return $this ->names = array($name0, $name1, $name2, $name3);
  }
}

class View {
  function __construct() {}

  function formNames() {
    echo "<form method=post name=\"form1\" action=\"mvcpractice4.php\"></ br><div class=\"row\"></ br>";
    for ($i = 0; $i < 4; $i++) {
       echo "<label for=\"length\">Enter first name: &nbsp; &nbsp;</label></ br>
             <input style=\"font-size:12pt\" type=\"text\" id=\"length\" name=\"name".$i."\" value=\"\" size=\"15\"/></ br>
             <br style=\"clear:left\"/></ br>";
       }
    echo "</div></ br><input style=\"font-size:12pt\" type=submit name=submit value=\"Compute\" ></ br>
          <input type=hidden name=submitted value=\"true\" >";
  }

  function viewNames($names) {
    echo "<table><th>Some Group</th>";
    for ($i = 0; $i < 4; $i++) {
       echo "<tr><td>".$names[$i]."</td></tr>";
    }
  echo "</table>";
  }
}


class Controller {
  private $p;

  function __construct() {
    $this -> p = new Model();
  }

  public function submitNames() {
    if (!isset($_POST['submitted']))
    return;

    if (isset($_POST['name0']) && isset($_POST['name1']) && isset($_POST['name2']) && isset($_POST['name3'])) {
       $this -> p -> updateNames($_POST['name0'], $_POST['name1'], $_POST['name2'], $_POST['name3']);
    }
  }

  function uploadNames() {
    $v = new View();
    $v -> formNames();
  }

  function loadNames() {
    $v = new View();
    $v -> viewNames($this -> p -> names);
  }
}

$cp = new Controller();
$cp -> uploadNames();
$cp -> submitNames();
$cp -> loadNames();

I want to apply the MVC concept to my Shape example. I realize that I haven't much of a clue how to do that. The main reason is that I can't see how to structure the classes. In the code snippet below, there is the Model class, the Shape class, and the Rectangle class that extends the Shape class.

class Model {

  function __construct() {}

    abstract class Shape {
      const density = '2.5';

      abstract public function getVolume() {};

      public function getWeight() {
        return self::density * $this -> getVolume();
      }
    }

      class Hexahedron extends Shape {
        private $length;
        private $width;
        private $height;
etc.

Is that corrrect? Is that possible? I am flying completely blind. I have not come across any clear examples of MVC that demonstrate this issue. Can the veteran masters of PHP please offer their opinions? Thanks in advance.

1

I wouldn't place a class within another class. If you want models to have some particular common functionality, then extend them from an abstract Model class. Typically you'd have the 3 directories:

Controllers/
  controller.php (abstract parent controller)
  shapes.php (concrete extends controller)

Models/
  model.php (abstract parent model)
  shape.php (abstract class extends model)
  square.php (concrete extends shape)
  circle.php (concrete extends shape)

Views/
  layouts/
   basic.php
   splash.php
  common/
   header.php
   footer.php
   navigation.php
  shapeData.php (can be a class or just HTML with placeholders for data fro controllers)

Controllers/Shape

class Shape extends Controller
{
    private $allowedShapes = ['circle','square']; 

    public function display($shape, $dims)
    {
        if(!in_array($shape, $this->allowedShapes) return false; //or display default or 404

        $obj = new $shape($dims);

        $data['area'] = $obj->get_area();
        $data['name'] = strtoupper($obj->get_name());
        $data['sides'] = $obj->get_sides();
        $data['dims'] = $obj->get_dims();

        return parent::make_view('Views/shapeData.php', $data); //Controller class method
    }
}

Models/Square

class Square exteds Shape
{
    private $sides = 4;
    private $length;
    private $name = 'square';

    public function __construct($dims)
    {
        $this->length = $dims;
        $this->dims = $this->length . ' x ' .  $this->length;
    }

    public function get_area()
    {
        return $this->length * $this->length;
    }
}

Views/shapeData.php

<h1><?=$data['name']?></h1>
<p>Dimensions: <?=$data['dims']?></p>
<p>Area: <?=$data['area']?></p>
<p>Sides: <?=$data['sides']?></p>

That's a quick knock-up. There are many ways of doing this I suppose. The Views, as I mentioned previously, and as shown by jkon, could be classes rather than naked markup with the odd bit of php. I have not shown all the methods here as this is just an example and a full build of an MVC is way beyond the scope of a form post.

Edited by diafol

0

Thanks, diafol. I will review your suggested code to understand as much of it as I can.

0

Well, thanks to everyone who posted replies to my questions, research on the topic, and trail and error experimentation, I was able to apply the MVC concept to my Shape example and get respectable results. I am posting the program below. I included code that I commented out to show how dramatically different (in my eyes) this version is from earlier ones. (I do get an undefined index error on the initial loading of the program.)

class Model {
   public function __construct() {
   }
}

abstract class Shape  {

//   abstract public function getVolume($length, $width, $height);

//   public function getWeight() {
//      return  * $this -> getVolume($length, $width, $height);
//   }
}

   class Hexahedron extends Shape {
      const density = '2.5';
//      public $length;
//      public $width;
//      public $height;

      public function dims() {
         return $dim = array("length", "width", "height");
      }

      public function names() {
         return $name = array("perimeter", "area", "volume", "weight");
      }

      public function chars($length, $width, $height) {
         $char[0] = 4 * ($length + $width + $height);
         $char[1] = 2 * ($length * $width + $length * $height + $height * $width);
         $char[2] = $length * $width * $height;
         $char[3] = self::density * $length * $width * $height;
         return $char;
      }

//      public function __construct($length, $width, $height) {
//         $this -> setLength($length);
//         $this -> setWidth($width);
//         $this -> setHeight($height);
//      }

//      public function setLength($length) {
//         $this -> length = $length;
//      }

//      public function setWidth($width) {
//         $this -> width = $width;
//      }

//      public function setHeight($height) {
//         $this -> height = $height;
//      }

//      public function getPerimeter($length, $width, $height) {
//         return $perimeter = 4 * ($length + $width + $height);
//      }

//      public function getArea($length, $width, $height) {
//         return $area = 2 * ($length * $width + $length * $height + $height * $width);
//      }

//      public function getVolume($length, $width, $height) {
//         return $volume = $length * $width * $height;
//      }

   }


class View {

    function __construct() {}

    function dimensions($dim) {
       echo "<form method=post name=\"form1\" action=\"mvcbpractice0.php\"></ br>";
       for ($i = 0; $i < 3; $i++) {
          echo "<div class=\"row\"></ br>
                <label for=".$dim[$i].">Enter ".$dim[$i].": &nbsp; &nbsp;</label>
                <input style=\"font-size:12pt\" type=\"text\" id=".$dim[$i]." name=".$dim[$i]." />
                <br style=\"clear:left\"/></ br>";
       }
       echo "<p>&nbsp;</p><input style=\"font-size:12pt\" type=submit name=submit value=\"Submit\" ></ br>
             <input type=hidden name=submitted value=\"true\" ></ br><p>&nbsp;</p>";
    }

    function characteristics($name, $char) {
       echo "<div class=\"row\">";
       for ($i = 0; $i < 4; $i++) {
          echo "<label for=".$name[$i]." id=".$name[$i]." style=\"font-size:13pt\">The " .$name[$i]. " of the rectangle is:</label>
          <input style=\"font-size:12pt\" type=text id=".$name[$i]." name=".$name[$i]." value=".$char[$i]." size=10 maxlength=10></td>
          <br style=\"clear:left\"/><br />";
       }
       echo "</div>";
    }
}

class Controller {
  private $p;
  private $v;
  private $w;

  function __construct() {
    $this -> p = new Hexahedron();
  }

  public function getForm() {
    $v = new View();
    $v -> dimensions($this -> p -> dims());
  }

  public function submitForm() {
    if (!isset($_POST['submitted']))
    return;

//    if (isset($_POST['length']) && isset($_POST['width']) && isset($_POST['height'])) {
//       $this -> p -> chars($_POST['length'], $_POST['width'], $_POST['height']);
//    }
  }

  public function displayForm() {
    $w = new View();
    $w -> characteristics($this -> p -> names(),$this -> p -> chars($_POST['length'], $_POST['width'], $_POST['height']));
  }
}

$cp = new Controller();
$cp -> getForm();
$cp -> submitForm();
$cp -> displayForm();

What have I learned about classes in PHP from this exercise? I learned a great deal. Like others who have learned about something, I learned about how much I still don't know about classes in PHP. I thought I was going to get more knowledge and insight about classes, and develop a framework or template for using classes. I learned that there really is no consistent framework or template for using classes. It depends on the problem that the program is being designed to solve.

In my Shape example, the Shape class itself became redundant in the MVC framework. I was able to comment out all the lines of code in that class with no impact on the program. If I do not make an Ellipsoid class, then the Hexahedron class can be renamed the Model class and I have a 'classic' MVC framework. I don't see the usefulness of inheritance in the MVC concept.

In the first versions, I had setter and getter functions as I have seen in countless examples in PHP tutorials. In the MVC framework, it seems that accessor/mutator functions are not needed. I see and appreciate the versatility of the MVC framework. I could easily adapt this final program to a circle from a rectangle by changing only the Model class. The View class need not chnage at all. I would need to change the variable names in the $_POST array in the Controller class. I see the large convenience of simply swapping in or out the Model class in developing programs about geometric shapes.

I wasn't expecting to learn this but I am approaching the conclusion that comprehensive programs that accomodate many contingencies or options, almost like one-size-fits-all, are not the way to go. It seems to me to be better to have highly specialized programs that do one thing excellently. There would need to be a 'triage' program (the Controller?) that could assess the user's needs and call up the specific programs from a library that meets those needs. Math program libraries are an example.

I would like comments on this final program over the next few days before I mark the thread as solved.

Thanks very much to everyone. I will have other practice programs in the near future.

0

I don't see the usefulness of inheritance in the MVC concept.

Inheritance is a bit of an odd one, but in MVC controllers usually extend a controller class and models extend a model class. An example of an inherited method from the abstract Shape class would be perimeter(). Where the formula could be identical in all polygons. However, ellipsoids or circles would have a different one, so you would over-ride the inherited method just for those special classes.

For abstract methods in the abstract parent, then these insist that the concrete children have that method (similar in a way but not the same as an interface).

I wasn't expecting to learn this but I am approaching the conclusion that comprehensive programs that accomodate many contingencies or options, almost like one-size-fits-all, are not the way to go. It seems to me to be better to have highly specialized programs that do one thing excellently.

OOP will not be purely "plug-and-play" - each project will be different. However, if you make your classes as "uncoupled" (or as "ignorant") as possible - you have the makings of re-usable code across projects - a burgeoning mini-framework even. By their nature, some classes will be highly specialized, but they should not be closely coupled with each other. Each class should have one job and one job only, otherwise you start throwing the kitchen sink into a black hole.

So, your abstract Controller and abstract Model shoould be the same across all projects (pretty much) or at least they'll give you the starting point for new ones. Some utility abstract classes/methods can be re-used, such as date/string manipulators - but equally you could create a bunch of utility functions - some would argue that this is better.

My 2p.

Edited by diafol

0

I have never understood why so much effort has been done to PHP OOP MVC understanding to pair a Controller with a model class. The model lives there without a Controller only simple inputs and it produces objects ( or an object that is a list of object). Many Controllers could use the same Model or a Controller can use many Models or Views. Fundamental business rule also leave in the Model (not validation). Can the Model have a validation layer ? Yes but this is a layer.

Nathanaiel I continue to see in your example things that are defiantly not PHP OOP , but are mix of PHP functional with procedural. This thread wasn't about MVC so there is no reason to explain why those examples brake the MVC symmetry. Even if this thread is only about OOP are you happy that a method dimensions($dim) (that is not declare public because you think it dirty OOP as well) do several things that don't belong to a single method (it computes and it output as well)

0

@Jkon,

Nathanaiel I continue to see in your example things that are defiantly not PHP OOP , but are mix of PHP functional with procedural.

I don't know what that means. What is functional PHP versus procedural PHP?

Even if this thread is only about OOP are you happy that a method dimensions($dim) (that is not declare public because you think it dirty OOP as well) do several things that don't belong to a single method (it computes and it output as well)

I am not sure of what this means either. The dimensions() function in the View class is not declared public because I overlooked that. My understanding is that when visibility is not declared it is public. What is "dirty" OOP?

The dimensions() function in the View class outputs the input form. I don't see where it is computing anything. Please explain.

Edited by Nathaniel10

0

The term “dirty” OOP as I used it , refers to writing in object oriented programming style bar keeping the same functional or even procedural logic. But I believe my own previous comments answers to me , meaning that as I wrote , in PHP there are several ways to write in OOP and various mixed of OOP with functional or even procedural , so no one can claim that his way is the “correct” one and some of the others aren't as clean OOP (or “dirty”). In your example you use many times arrays when actually you are describing an object , for example the chars method of the Hexahedron. So I believed I answered my self about that.

Now lets move to your code (again here are only some thought that comes out my understanding). First of all you have no reason to create triads of Model View Controller classes. A Controller can use as many model classes needed as many view classes also, of course final one view template class (or a template file) will produce the final outcome using the current Controller (would be preferable if this use has no logic inside the View class). In your example the View class doesn't return anything to the Controller , it just echoes what is needed.

Modifying html that is generated through echo is hard (in my opinion) and produces code that is harder to read. The same example you gave if it were to return a string to the Controller and then the Controller use it to provided to the final view template class (or file) , would be something like that: (notice that here without a framework or even a library we will do it from scratch (that is not the best idea in real life , also here I used almost your actual html code just adding what whas missing (example </form> or change the </ br> to <br/>) ) . Also here I assumed the dims method has declared as abstract method in the Shape class).

abstract class View_Abstract
{
  abstract function generate();
}

class View_Shape_Form extends View_Abstract
{
  /**
   * @var Shape
   */
  private $shape;

  public function __construct(Shape $shape)
  {
    $this->shape = $shape;
  }


  public function generate()
  {
    $formInputs = "";
    $dims = $this->shape->dims();
    if(is_array($dims) && count($dims) > 0)
    {
      $viewFormInput = new View_Shape_FormInput();
      foreach($dims as $dim)
      {
        $viewFormInput->setInputName($dim);
        $formInputs .= $viewFormInput->generate();
      }
    }

    ?>
<form method=post name="form1" action="mvcbpractice0.php">
    <br />
    <?=$formInputs?>
    <p>&nbsp;</p>
    <input style="font-size: 12pt" type=submit name=submit value="Submit" />
    <br />
</form>
    <?php
  }
}

class View_Shape_FormInput extends View_Abstract
{
  private $inputName;

  public function setInputName($inputName)
  {
    $this->inputName = $inputName;
  }

  public function generate()
  {
    if(isset($this->inputName))
    {
      ?>
<div class="row">
    <br /> <label for="<?=$this->inputName?>"> Enter "<?=$this->inputName?>":
        &nbsp; &nbsp; </label> <input style="font-size: 12pt" type="text"
        id="<?=$this->inputName?>" name="<?=$this->inputName?>" />
</div>
      <?php
    }
  }
}

Now back to your Controller I added a method viewGenerator and I change the getForm method

  public function viewGenerator(View_Abstract $view)
  {
    ob_start();
    $view->generate();
    $re = ob_get_contents();
    ob_end_clean();
    return $re;
  }

  public function getForm() {
    $view = new View_Shape_Form($this->p);
    return $this->viewGenerator($view);
  }

Now after instantiating the Controller you can use to output what its getForm method returns or in another View or in your case in the same file.

0

@Jkon,

In your example you use many times arrays when actually you are describing an object , for example the chars method of the Hexahedron.

This makes no sense to me. As I understand it, an object is an instance of a class. Instantiation occurs with the statement $objectName = new className;. I do not use the method chars() nor the related variable $char as an instance of the Model class. I use $char as a data structure. To my knowledge, objects are not variables and variables are not objects. Correct me if I am wrong.

First of all you have no reason to create triads of Model View Controller classes.

I think I said that when I wrote that the Shape class became redundant in the MVC framework of this example. I would not have learned that nor, more importantly, understood why, if I had not gone through the exercice of adapting the MVC concept to my Shape example. It sounds like you, and Diafol earlier, are referring to Hierarchical MVC. The tutorial in this site shows that one can have super- and subclasses for the Model, View, and Controller with inheritances between the parents and children. I found it easier to understand an abstract Shape super-class with concrete sub-classes of 4-sided solids, 6-sided solids, 8-sided solids, and ellipsoid solids, than the potential HMVC representation of such a situation.

I have come accross PHP examples which use 'echo' to display HTML code or store HTML code in a variable and print the variable when needed. I use both. I admit that the 'echo' technique is simpler for me and I prefer to use it when there is more complex HTML code to deal with. I use the variable technique when the HTML is less complex, such as for error messages of a few sentences enclosed in paragraph tags.

In your prior post, you wrote about my not declaring a function as public. I did some experimentation on the visibility of the functions in the MVC example. I found that because the Controller class must access the functions in the Model and View classes, ALL the functions in those two classes MUST be public. Furthermore, the functions in the Controller class also MUST be public so they can be accessed by the user from outside that class. I also confirmed that when a function's visibility is not explicitly stated it is public by default. Given that functions must be public and that is the default visibility, it is redundant to declare functions as public in the MVC framework. When I use the MVC framework in the future, I will omit the explicit public declaration in the code and write a comment explaining why.

I appreciate that you wrote code that improves on what I wrote. I learn very well by comparing how I approached solving a problem to how others approached solving the same problem. However, I have difficulty following your code. I need to study it for hours.

I did more research on MVC. I read debates on whether form validation should take place in the Controller class or the Model class. The most intelligent comments were that the validation of things that are common to many situations, such as email validation, are better of in the Controller class. The validation of things that are unique to a particular Model should be in that class. For what it's worth, I moved the form validation from the Controller class to the Model class, in my example.

class Model {
   public function __construct() {
   }
      const density = '2.5';
      const pi = '3.14159265359';

            // The following function, valid(), validates the data being posted from the form for use in making computations regarding the spheroid.
            // It also moves the data into the array called 'measure'.

      public function valid() {
         if (isset($_POST['x_radius']) && isset($_POST['y_radius']) && isset($_POST['z_radius'])) {
            if (is_numeric($_POST['x_radius']) && is_numeric($_POST['y_radius']) && is_numeric($_POST['z_radius']) &&
               $_POST['x_radius'] >= 0 && $_POST['y_radius'] >= 0 && $_POST['z_radius']) {
               $measure[0] =  array_key_exists('x_radius', $_POST) ? $_POST['x_radius'] : null;
               $measure[1] =  array_key_exists('y_radius', $_POST) ? $_POST['y_radius'] : null;
               $measure[2] =  array_key_exists('z_radius', $_POST) ? $_POST['z_radius'] : null;
            } else {
               echo "Please enter numeric, non-negative values.";
            }
         return $measure;
         }
      }

            //  The following function, dims(), creates the array that holds the names of the posted and validated data, the dimensions of the spheroid.

      public function dims() {
         return $dim = array("x_radius", "y_radius", "z_radius");
      }

            //  The following function, names(), creates the array that holds the names of the computed output, the characteristics of the spheroid.

      public function names() {
         return $name = array("maximum circumference", "surface area", "volume", "weight");
      }

            // The following function, chars(), computes the characteristics of the spheroid; circumference, area, volume, and weight.
            //  It also moves the results into the array called 'char'.

      public function chars($measure) {
         $char[0] = 2 / pow(2, 0.5) * self::pi * (pow(($measure[0] * $measure[0] + $measure[1] * $measure[1]), 0.5) +
                    pow(($measure[0] * $measure[0] + $measure[2] * $measure[2]), 0.5) +
                    pow(($measure[1] * $measure[1] + $measure[2] * $measure[2]), 0.5));
         $char[1] = 4 * self::pi * pow((pow(($measure[0] * $measure[1]), 1.6) + pow(($measure[0] * $measure[2]), 1.6) +
                    pow(($measure[2] * $measure[1]), 1.6))/3, 0.625);
         $char[2] = 4/3 * self::pi * $measure[0] * $measure[1] * $measure[2];
         $char[3] = self::density * $char[2];
         return $char;
      }
}


class View {
   public function __construct() {}

            // The following function, dimensions(), creates the input form populated with the names of each dimension.
            // The argument, the array dim, provides those names.

      public function dimensions($dim) {
         echo "<form method=post name=\"form1\" action=\"mvcbpractice1.php\"></ br>";
         for ($i = 0; $i < 3; $i++) {
            echo "<div class=\"row\"></ br>
                  <label for=".$dim[$i].">Enter ".$dim[$i].": &nbsp; &nbsp;</label>
                  <input style=\"font-size:12pt\" type=\"text\" id=".$dim[$i]." name=".$dim[$i]." />
                  <br style=\"clear:left\"/></ br>";
         }
         echo "<p>&nbsp;</p><input style=\"font-size:12pt\" type=submit name=submit value=\"Submit\" ></ br>
             <input type=hidden name=submitted value=\"true\" ></ br></form>";
      }

            // The following function, characteristics(), creates the output form populated with the names and values of each characteristic;
            // circumference, area, volume, and weight.
            // The arguments, the arrays name and char, provides those names and values respectively.

      public function characteristics($name, $char) {
         echo "<p>&nbsp;</p><div class=\"row\">";
         for ($i = 0; $i < 4; $i++) {
            echo "<label for=".$name[$i]." id=".$name[$i]." style=\"font-size:13pt\">The " .$name[$i]. " of the spheroid is:</label>
            <input style=\"font-size:12pt\" type=text id=".$name[$i]." name=".$name[$i]." value=".$char[$i]." size=10 maxlength=10>
            <br style=\"clear:left\"/><br />";
         }
         echo "</div>";
      }
   }

class Controller {
   private $p;
   private $v;
   private $w;

   public function __construct() {
     $this -> p = new Model();
   }

      public function getForm() {
        $v = new View();
        $v -> dimensions($this -> p -> dims());
      }

      public function submitForm() {
        if (!isset($_POST['submitted']))
        return;
      }

      public function displayForm() {
        $w = new View();
        $w -> characteristics($this -> p -> names(),$this -> p -> chars($this -> p -> valid()));
      }
}

$cp = new Controller();
$cp -> getForm();
$cp -> submitForm();
$cp -> displayForm();

Edited by Nathaniel10

1

I will try to keep this answer short. I understand that you are now learning OOP , you are following tutorial that mix PHP functional with OOP or you create your own mix. Either way , I believe we are not here to judge , just help you see one other perspective about OOP with PHP as you asked in first place.

As I understand it, an object is an instance of a class. Instantiation occurs with the statement $objectName = new className;. I do not use the method chars() nor the related variable $char as an instance of the Model class. I use $char as a data structure. To my knowledge, objects are not variables and variables are not objects. Correct me if I am wrong.

What do you return in the method chars ? Even its name would be helpful to answer to that question. You return an array containing circumference, area, volume, and weight , why don't you return an object ? An instance of a class (object) can be a variable , so you can return a variable – instance of an object there. In my point of view that makes the code really easier to read , modify , apply logical rules to it and be reusable. If you stop thinking data structures and start thinking about objects you will be one step closer of understanding OOP , in my point of view. The extensive use of associative arrays indicates where they describe a data structure and not just a map , is far away from OOP in my opinion.

It sounds like you, and Diafol earlier, are referring to Hierarchical MVC

I didn't even touched what HMVC is and surely none of the examples used HMVC. To explain you what is , I would need more than a paragraph but just to understand that this has nothing to do with what you are saying , HMVC involves the ability of a Controller (or in some implementation directly the View) to use other Controllers (with their own Models and Views). That the Controller can use as many Model and View classes needed has nothing to do with HMVC.

I have come accross PHP examples which use 'echo' to display HTML code or store HTML code in a variable and print the variable when needed. I use both.

As you see in the examples I gave you the html parts are solely html and every variable that came from PHP is output by <?= . This allows you to have your html parts isolated from the other class parts , you can modify them easy , even use your favorite html editor , or work with other that produce front end without you having to enter those parts inside your code with echo or variables that mixes together finally going through echo process. Also I found it very helpful not echoing anything before all the logic ends , separating the final view help you in many ways (exceptions , errors , debugging , redirections , headers and more).

I found that because the Controller class must access the functions in the Model and View classes, ALL the functions in those two classes MUST be public. Furthermore, the functions in the Controller class also MUST be public so they can be accessed by the user from outside that class. 

This is not the case. Public must be methods or properties of an object that are accessed by other objects (if it is only from their child then are protected). Many times a public method of an instance – object of a Model class might need to use other methods of the same instance that there is no reason or even shouldn't be exposed as public. This goes for View classes as well , but I understand that it is not as common there.

When I use the MVC framework in the future, I will omit the explicit public declaration in the code and write a comment explaining why.

You can do what ever you like , of course I don't understand why not every method – function and property – variable of a class shouldn't have its visibility declaration (public,protected,private) visible.

The most intelligent comments were that the validation of things that are common to many situations, such as email validation, are better of in the Controller class.

There are also utilities classes. Common validations could be in a validation util class or even group them together group them together in different Utils by their scope. The same goes for example for a StringUtil class not only for function names nonresistances of PHP with strings handling but also to put in place all this mb_ zoo.

I appreciate that you wrote code that improves on what I wrote ... However, I have difficulty following your code. I need to study it for hours.

We are here to ask when you don't understand something. Of course you can have your own opinions or accept something you read in one of so many PHP tutorials that sounds more logical to you. What ever you choose I would suggest first to understand some of the basic differences of the solutions proposed and then make a lot of your own tests.

0

Wise words there jkon. I would add here that not every small project requires MVC. I can't really see the need for your example to be in this category of projects, mainly because I have no idea about the scope of it or how it integrates with other bits of code that you have.

Visibility - ironic that you don't want the visibility to be visible. Heh heh. Yes we are aware that we default to public in its absence, but current coding "good practice", seems to point to explicitly declaring it. You may feel this is "stating the obvious", but I'm of the opinion that it helps with readability. If I see the word 'public', it's much easier to zoom in on that in a long block of methods than look for an absence of visibility. But that is a personal preference. Many more experienced programmers than myself have adopted the "don't show the public keyword". Just as long as you don't use var, you should be fine.

Validation can be a tricky one, but I would say that this is a utility and not specific to any single model or controller. The controllers can call public (or abstract) validation methods from a Validation object (or class) before calling methods from Models - could be one way of doing it.

This question has already been answered. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.