Monday, September 13, 2010

PHP - Visibility (public, private, protected)

Visibility (public, private, protected)

The visibility of class members, (properties, methods), relates to how that member may be manipulated within, or from outside the class. Three levels of visibilty exist for class members.
  • public
  • private
  • protected
By default, all class members are public. This means if you do not declare a property or method within the class, it will be public. It is good practice to declare the visibility of class members for the sake of readability for yourself and others. It is much easier for another programmer to see your intentions. This will also future proof your scripts should access modifiers be deprecated.
Public class members (properties and methods) are available through-out the script and may be accessed from outside the class as we demonstrated in our car class. Lets create a simple new class to demonstrate.


class mathematics{/*** a  number ***/public $num;
/**
*
* Add two to a number
*
* @access public
*
* @return int
*
**/
public function addTwo(){
  return 
$this->num+2;
}

}
/*** end of class ***/

/*** Instantiate a new class instance ***/
$math = new mathematics;
/*** set the value of the number ***/$math->num 2;
/*** call the addTwo method ***/echo $math->addTwo();
?>
We can see in the above example that the public variable $num is set from user space and we call a public method that adds two the number and returns the value of $num+2. Having our properties (variables) visible, or accessible from any part of our script works in our favour here, but it can also work against us. A could arise if we lost track of our values and changed the value of $num. To counter this problem we can create a method to set the value for us. Even with this in place it is still possible for somebody to simply access the $num variable. So we make the variable private. This ensures us that the property is only available within the class itself. It is private to the calling class. Consider the following code.



class mathematics{
/*** a  number ***/private $num;
/**
*
* Set the value of $num
*
* @access public
*
* @param $num The number to set
*
* @return int
*
**/
public function setNum($num){
  
$this->num $num;
}
/**
*
* Add two to a number
*
* @access public
*
* @return int
*
**/
public function addTwo(){
  return 
$this->num+2;
}

}
/*** end of class ***/

/*** Instantiate a new class instance ***/
$math = new mathematics;
/*** set the value of the number ***/$math->setNum(2);
/*** call the addTwo method ***/echo $math->addTwo();
?>
?>
Any further attempt to reset the $num property without the setNum() method would result in a Fatal Error such as
Fatal error: Cannot access private property mathematics::$num in /www/mathematics.class.php on line 43
Even if you were to try to access the private $num property from a child class it would fail. This is because private methods and properties in a parent class are not visible to child classes and cannot be accessed. To access a parent method or property from a child class you need to use the protected keyword. Like the private keyword, protetected methods and properties are available only to the class that created them. But unlike private, protected methods and properties are visible from a parent class. Lets see how this works.

class mathematics{/*** a  number ***/protected $num;
/**
*
* Set the value of $num
*
* @access public
*
* @param $num The number to set
*
* @return int
*
**/
public function setNum($num){
  
$this->num $num;
}
/**
*
* Add two to a number
*
* @access public
*
* @return int
*
**/
public function addTwo(){
  return 
$this->num+2;
}

}
/*** end of class ***/
class divide extends mathematics{
/**
*
* Divide a number by two
*
* @access public
*
* @return int
*
**/
public function divideByTwo(){
  
/*** divide number by two ***/
  
$new_num $this->num/2;
  
/*** return the new number and round to 2 decimal places ***/
  
return round($new_num2);
}

/*** end of class ***/

/*** Instantiate a new class instance ***/
$math = new divide;
/*** set the value of the number ***/$math->setNum(14);

echo 
$math->divideByTwo();
?>
We can see here the the user space code has called the setNum() method in the parent mathematics class. This method, in turn, sets the $num property. We are able to do this because the $num property has been declared protected and is visible to the child class.

Final

As we saw in the previous section there are ways to protect your code from being used in an improper manner. Another way of protecting yourself is the Final keyword. Any method or class that is declared as Final cannot be overridden or inherited by another class. Lets put it to the test.

final class mathematics{

/*** end of class ***/
class divide extends mathematics{

}
?>
By running the above code you will get an error such as
Fatal error: Class divide may not inherit from final class (mathematics) in /www/final.php on line 8
This can protect us from those who wish to use our code for a purpose other than that for which it was intended.

Abstract Classes

An abstract class is a class that cannot be instantiated on its own. You cannot create a new object from it. To see this lets make a basic class.

abstract class mathematics{
/**
*
* Add two to a number
*
* @access public
*
* @return int
*
**/
public function addTwo(){
  return 
$this->num+2;
}

/*** end of class ***/

/*** try to create new object from the mathematics class ***/
$math = new mathematics

?>
Using the code above, you will get an error something like this
Fatal error: Cannot instantiate abstract class mathematics in /www/abstract.php on line 23.
As you can see, this is not allowed. Also if you declare any class method to be abstract, you must also declare the class itself as abstract too. So, whats the point you ask? Well, you can inherit from an abstract class. Any class that extends an abstract parent class must create an interface of the parent abstract methods. If this is not done a fatal error is generated. This ensures that the implementation is correct.

abstract class mathematics{/*** child class must define these methods ***/abstract protected function getMessage();

abstract protected function 
addTwo($num1);
/**
*
* method common to both classes
*
**/
public function showMessage() {
  echo 
$this->getMessage();
}

/*** end of class ***/
class myMath extends mathematics{/**
*
* Prefix to the answer
*
* @return string
*
**/
protected function getMessage(){
  return 
"The anwser is: ";
}
/**
*
* add two to a number
*
* @access public
*
* @param $num1 A number to be added to
*
* @return int
*
**/
public function addTwo($num1) {
  return 
$num1+2;
}

/*** end of class ***/

/*** a new instance of myMath ***/
$myMath = new myMath;/*** show the message ***/$myMath->showMessage();/*** do the math ***/echo $myMath->addTwo(4);
?>

Static Methods and Properties

The use of the static keyword allows class members (methods and properties) to be used without needing to instantiate a new instance of the class. The static declaratin must come after the visibility declaration, eg:
public static myClass{
Because there is no object created when using a static call, the keyword $this and the arrow operator, -> are not available. Static variables belong to the class itself and not to any object of that class. To access withing the class itself you need to use the self keyword along with the :: scope resolution operator. Lets whip up a quick example of using static.
/*** a simple class ***/class myClass{/*** a static variable ***/ static $foo;
}
/** give the static variable a value ***/myClass::$foo 'Bar';
/*** echo the static variable ***/echo (myClass::$foo ).?>
The above snippet will echo
Bar This is rather basic as an example, so lets use something practical. Static properties are often used as counters. Here we will use a basic counter class.
class counter{
/*** our count variable ***/private static $count 0;
/**
* Constructor, duh
**/
function __construct() {
  
self::$count++;
}
/**
*
* get the current count
*
* @access public
*
* @return int
*
**/
public static function getCount() {
 return 
self::$count;
}

/*** end of class ***/

/*** create a new instance ***/
$count = new counter(); /*** get the count ***/echo counter::getCount() . '';/*** create another instance ***/$next = new counter(); /*** echo the new count ***/echo counter::getCount().''/*** and a third instance ***/$third = new counter;
echo 
counter::getCount().'';?>
Hopefully by the end of the above snippet you can see what is happening. At each new instance the counter class we increment by one. Not also the use of the :: scope resolution operator and self keyword to refer to the static variable within the class itself.

Interfaces

Interfaces in PHP allow you to define a common structure for your classes. An interface cannot be instantiated on its own. One of the goals of OOP is re-use of code. Interfaces make this a much easier process. The interface methods have no internal logic, they are simply a "mapping" or constraint of what the class, or classes, should implement. Here we will demonstrate how this works using our vehicle class from earlier, with the addition of a stop() function.
class vehicle implements testdrive{
/*** define public properties ***/

/*** the color of the vehicle ***/
public $color;
/*** the number of doors ***/public $num_doors;
/*** the price of the vehicle ***/public $price;
/*** the shape of the vehicle ***/public $shape;
/*** the brand of vehicle ***/public $brand;
/*** the constructor ***/public function __construct(){
  echo 
'About this Vehicle.';
}
/*** define some public methods ***/

/*** a method to show the vehicle price ***/
public function showPrice(){
  echo 
'This vehicle costs '.$this->price.'.';
}
/*** a method to show the number of doors ***/public function numDoors(){
  echo 
'This vehicle has '.$this->num_doors.' doors.';
}
/*** method to drive the vehicle ***/public function drive(){
  echo 
'VRRROOOOOOM!!!';
}
/**
* a method to stop the car
*
* @access public
*
**/
public function stop(){
  echo 
'SSSCCRRREEEEEECCHH!!!';
}

/*** end of class ***/

/*** declare our interface ***/
interface testdrive{/*** some functions that must be implemented ***/function drive();
function 
stop();
}
/*** an new vehicle object ***/$object = new vehicle;
/*** call some methods ***/$object->drive();$object->stop();?>
You may of course create multiple classes to implement your interface, but they will not inherit from each other. When you inherit from a parent class, you may choose to override some of parent methods. If you had multiple parent class methods with the same name, but different functionality or charactaristics, PHP would have no way of telling which of these methods to use. This is why multiple inheritance does not work in PHP. In contrast, classes that implement an interface, must implement every method so there is no ambiguity.
In the real world interfaces provide us with the tools harness parts of multiple classes. Consider this scenario. If we had two classes, one for a fax and the other for a printer. Each has seperate uses and could be described like this:

class fax{
  public function 
dial();
  public function 
send();
  public function 
recieve();
}

class 
printer{
  public function 
printBlack();
  public function 
printColor();
  public function 
printDraft();
}
?>
Both of the above classes give the required usage for each item, but they do not take into consideration the existance of a printer/fax machine. To get the usage of both classes we would do something like this:

class fax{
  public function 
dial();
  public function 
send();
  public function 
recieve();
}

class 
printer extends fax{
  public function 
printBlack();
  public function 
printColor();
  public function 
printDraft();
  public function 
kick();
}

class 
printerFax extends fax{
}
$object = new printerFax;?>
This code works by creating a stack of classes. The grandparent class is fax. Then the printer class extends the fax class and inherits all the methods from that class. This is where some problems may arise. The printer class now has the function dial() available to it which is clearly going to cause some confusion and possibly errors in logic.
To counter this problem an interface can be used to tell the classes what functions (methods) are required. Lets look at the design.

interface fax{
  public function 
dial();
  public function 
send();
  public function 
recieve();
}

interface 
printer{
  public function 
printBlack();
  public function 
printColor();
  public function 
printDraft();
  public function 
kick();
}

class 
printerFax implements faxprinter{
  public function 
dial(){ }
  public function 
send(){ }
  public function 
recieve(){ }
  public function 
printBlack(){ }
  public function 
printColor(){ }
  public function 
printDraft(){ }
  public function 
kick(){ }
}

  
$object = new printerFax;?>
Before we go further, it is recommended you run the above code. It will produce no output but we need to be sure all is well. Having run the code, remove the line
public function kick(){ }
and run it again. What you should now get is an error such as:
Fatal error: Class printerFax contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (printer::kick) in /www/oop.php on line 22
With the kick() function removed from our implementation, we have essentially broken the contract that says we will implement every function (method) specified in the interface. We can gather these functions fractionally from multiple classes, but we MUST have them all or we will get errors such as the one above.
Interfaces play a major role in with SPL and it is recommend you implement the interfaces from SPL and not just the class methods.

No comments:

Post a Comment