Probing the oop capabilities of PHP

Hi I am trying to explore the class & object facilities written into PHP.
I have a new 64bit computer with a quad processor running on a Windows vista Business OS, I have loaded PHP v5.2.14 which may or may not have all of the required configuration file extensions included. I am using IIS.
I have written two PHP files, one which contains only the class code and another which calls it and displays the value of the class property (one only to begin with for simplicity).

File product.php


<?php
class Ch2_Product
{
  // properties defined here
//  protected $_type = 'Book';

  // methods defined here
//  public function getProductType()
//  {
//    return $this->_type;
//  }
//  public function setProductType($type)
//  {
//    $this->_type = $type;
//  }
}

File product_test.php


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.3.org/1999/xhtml">
<head>
<title>Experimenting with visability</title>
<meta http-equiv="content-type"
   content="text/html; charset=iso-8859-1" />
</head>
<body>
<?php
  // include the class file
  require_once 'Product.php';
//  require_once(dirname(__FILE__) . "Product.php");


  // create an instance of the Ch2_Product class
  $product = new Ch2_Product();

  // display the $_type property
//  echo $product->_type;

</body>
</html>

launching the file called product_test I get a 500 error message (not able to display the page. I have edited out most of the code to try and find the source of the error without success and now wonder if there is something further required doing with the configuration file, todate the only extensions activated are the two mysql extensions (Which I am not using yet) The extension_dir & session.save_path have both been set.
Has anyone in this forum covered this ground and can offer a suggestion why the page cannot be displayed?
Thanks for any assistance in anticipation.

No. If you use ‘Go Advanced’ instead of using ‘Post Quick Reply’, you’ll find a couple of buttons that allow you to add <code> or <php> tags, and there’s even a drop down box with more advanced code tags. Just put your code between those tags.

:slight_smile: :slight_smile:

I would have thought so as well but since the only change the OP made was uncomment this line

require_once '../Ch2/DVD.php';

and if there is no previous other include or require of that file elsewhere in the code then that was worth a try.

Without seeing all the code (which is probably impractical to post) sometimes “brainstorming” possible solutions can help.

When you post code, put it between the appropriate bb code tags, please.

check you are not including product.php more than one (or use require_once to include them)

Also get PHP 5.3 and up, if you want to really use the OOP.

Understand. And I didn’t really want to make things too easy for the original poster. Better to explain the principle and then let the user figure out the details.

Notice how DVD.php includes the Product.php file.

I suspect that not having any methods in DVD.php could be the problem since it is an extension of the Ch2_Product class.

For Ch2_product to see the properties and methods of the parent class you will need

 
parent::__construct();

in the constructor of the sub-class along with any other constructor statements for the subclass.

Try adding at least the above line in the constructor for DVD.php and see if that helps.

Maybe with nothing in the subclass, php is seeing the subclass as a redeclaration of the parent class.

accessors… a completely different topic (and also they’re entirely redundant and pointless :p).

@OP it sounds like your IIS set up is wrong, when i used IIS I remember having to modify the web.config file to make it display PHP errors correctly.

Nothing wrong with encapsulation but accessors are just the same as public properties

If all you’re doing is wrapping class members, it just leads to more verbose code (both ends), higher development time and no real benefit.

Occasionally, however, they’re useful:

-Interfaces don’t support variables so when programming around interfaces and you need the client code to specify a variable an accessor is the only way

-Because PHP is dynamically typed, setters can be used to enforce types (By type hinting in the parameter)

I suppose you could argue consistency, but imho, that’s not a fair trade off for writing potentially hundreds of lines of redundant code.

I don’t see why you have

 
echo $product->_type;

when $_type in your class is set as protected.

You should be using your accessor method

getProductType().

 
 
echo $product->getProductType();

If you like, try this Book class and test code to see if your error is related to your code or php configuration.

<?php
class Book {
//properties
private $title;
private $author;

//------------------------------------------------------------

public function __construct($newTitle, $newAuthor) {
$this->title = $newTitle;
$this->author = $newAuthor;
}

public function setTitle($newTitle) {
$this->title = $newTitle;
}

public function setAuthor($newAuthor) {
$this->author = $newAuthor;
}

public function getTitleCOLOR=#007700 {[/COLOR]
return $this->title;
}

public function getAuthorCOLOR=#007700 {[/COLOR]
return $this->author;
}

} //end of class. The above code would normally be stored in a separate php file

//testing code

//first create 2 new books
$mybook1 = new Book(‘OOP is Great’,‘Fred Smith’);
$mybook2 = new Book(‘I like OOP’,‘Sam Jones’);

//now display the current values stored in each book
echo 'Book 1 title = '.$mybook1->getTitleCOLOR=#007700.[/COLOR]‘<br />’;
echo 'Book 1 author = '.$mybook1->getAuthorCOLOR=#007700.[/COLOR]‘<br />’;
echo 'Book 2 title = '.$mybook2->getTitleCOLOR=#007700.[/COLOR]‘<br />’;
echo 'Book 2 author = '.$mybook2->getAuthorCOLOR=#007700.[/COLOR]‘<br /><br />’;

//now change some values in each book
$mybook1->setTitle(‘OOP is Great - 2nd Edition’);
$mybook2->setAuthor(‘John Smith’);

//now display the current values stored in each book
echo 'Book 1 title = '.$mybook1->getTitleCOLOR=#007700.[/COLOR]‘<br />’;
echo 'Book 1 author = '.$mybook1->getAuthorCOLOR=#007700.[/COLOR]‘<br />’;
echo 'Book 2 title = '.$mybook2->getTitleCOLOR=#007700.[/COLOR]‘<br />’;
echo 'Book 2 author = '.$mybook2->getAuthorCOLOR=#007700.[/COLOR]‘<br /><br />’;
?>

Hi ahundiak, many thanks for your reply, I have adjusted the “require_once ‘Product.php’;” to “require_once ‘…/Ch2/Product.php’;” in the child file DVD.php and it performs successfully.
I have then edited the test file to call both child classes as was the original intention and so long as I call the parent class from the child class using a URL from the root directory “‘…/Ch2/Product.php’;” it continues to work.
This raises another question: since both child classes & the parent class reside in the same directory why can I not call the parent class from the child classes with the shorter “require_once ‘Product.php’;” after all the “require_once” should not now be confused into thinking the file being called from the two child classes is not the same file? But it does and I get a 500 error?
Bottom line all calls from child to parent class require to come through the root directory?
Hope this conveys what I intend to say, best regards.
P.S. There is a lot to digest in ca3.php.net//language.oop5.autoload.php this will take a little time for me to in. Thanks for pointing me to it.

Hi guido2004, sorry the reference to bb-code markup by kyberfabrikken went over my head - what is a bb-code markup? Are we talking HTML <b></b> bold tags?

TomB, I have used only require_once to call the main class file “Product.php” I have called it in the test file listed at the top of my code above and again in the child class, Im not sure of what the “require_once” blackbox contains but its name suggests that it protects against the file containing, in this case, the parent class being called twice possibly by checking if certain values are set. However multiple child classes need to call their parents how else can they inherit the parent properties & methods? This condition will continue when the test file is edited and a second child Ch2_Book replaces the direct call to Ch2_Product with an indirect call via the second child class.
Note:- I have an error message this time instead of the previous 500 error message (not able to display the page) when I add the second child it reverts back to the 500 error. Any suggestions how to avoid declairing the parent class more than once? (unless it goes global!)
Thanks again in anticipation.

require_once ‘…/Ch2/Product.php’;
vs
require_once ‘Product.php’;

System thinks they two different files and thus includes them twice.

Once you get past this hurdle take a look at autoloading to see how to implement load on demand functionality.
http://ca3.php.net/manual/en/language.oop5.autoload.php

Nope nope nope. Perfectly fine to extend a class without adding methods or instance variables. Problem, as already noted by several other posters, is that Product.php is being included more than once.

I was a bit surprised myself that require_once didn’t resolve the paths properly. Taking into account multiple operating system and such, it’s actually a somewhat difficult problem to solve. You can google for some of the discussions on it.

The other piece of the puzzle that you will want to look at is setting the include path. Once the include path is set then you can use relative file paths.
http://ca3.php.net/manual/en/function.ini-set.php

Assume you have
/home/user/classes/CH1/ (Some CH1 classes)
/home/user/classes/CH2/ (Some CH2 classes)


// Point the include path to your classes base directory
ini_set('include_path','.' . PATH_SEPARATOR . '/home/user/classes');

// and then include with
require_once 'CH2/Product.php';

Now your classes can live anywhere in the file system.

Hi can anyone explain the error message that I have on screen?
PHP Fatal error: Cannot redeclare class Ch2_Product in C:\inetpub\wwwroot\Ch2Visability\ch2_exercises\Product.php on line 3
I am adding child classes to the original project discussed above and get an error 500 unable to display. I have then backtracked in order to locate the problem (back to the main class)

Test file

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.3.org/1999/xhtml">
<head>
<title>Experimenting with visability</title>
<meta http-equiv="content-type"
   content="text/html; charset=iso-8859-1" />
</head>
<body>
<?php
  // include the class file
  require_once '../Ch2/Product.php'; // added to revert back to accessing main class
//  require_once '../Ch2/Book.php';
//  require_once '../Ch2/DVD.php';

  // create an instance of the all classes
  $product1 = new Ch2_Product('Book', 'PHP Object-Oriented Solutions');  // edited to Ch2_Product
  $product2 = new Ch2_Product('DVD', 'Atonement');             // edited to Ch2_Product

  // display the $_type property
echo '<p>$product1 is a ' . $product1->getProductType();
echo ' called "' . $product1->getTitle() . '"</p>';
echo '<p>$product2 is a ' . $product2->getProductType();
echo ' called "' . $product2->getTitle() . '"</p>';
?>
</body>
</html>

This works, I have now introduced one of the child classes with the following changes

// include the class file
  require_once '../Ch2/Product.php'; // added to revert back to accessing main class
//  require_once '../Ch2/Book.php';
  require_once '../Ch2/DVD.php';     // removed edit slashes to include the file with child class Ch2_DVD

  // create an instance of the all classes
  $product1 = new Ch2_Product('Book', 'PHP Object-Oriented Solutions');  // edited to Ch2_Product
  $product2 = new Ch2_DVD('DVD', 'Atonement');             // edited to Ch2_DVD

This change has produced the above error, but I cant see where the class “Ch2_Product” has been redeclaired?
It is declaired in the file Product.php but where else?

File Product.php

<?php
class Ch2_Product
{
  // properties defined here
  protected $_type;
  protected $_title;

  // constructor
  public function __construct($type, $title)
  {
    $this->_type = $type;
    $this->_title = $title;
  }

  // methods defined here
  public function getProductType()
  {
    return $this->_type;
  }
  public function getTitle()
  {
    return $this->_title;
  }
}

File DVD.php with child class

<?php

require_once 'Product.php';

class Ch2_DVD extends Ch2_Product
{
  // class definition goes here
}

The child class contains no properties or methods yet which should make it identical to the parent.

Hi Kalon, thanks for the bit of oop code, I have copied it into two files test & class and it worked first time as expected.

I think I can see what you are saying from the point of view that since php is not a compiled language, anyone you give the class to use can change the code to remove accessor methods and access properties directly if they are declred public.

But I guess I am influenced by my Java programming days where the code is compiled and programmers could not access class properties directly or even see what they were called if accessor methods were used to access properties and all the programmer had was the executable class file and not the source file.

I guess I still try to use the concept of encapsulation as much as possible in php.

This doesn’t work for parse errors, as the error happens before the file is executed, and so before the ini setting is changed. Better to set it in php.ini.