<?php
//1. Class and object
/*
object-oriented concept
an object can be almost any items or concept- a physical object(table) or conceptual software component(file)
an object is a unique and identical collection of stored data and operations that operate on that data
class attributes are properties or member variables
class operations are methods or Functions,actions, support overloading
Three features:
1.encapsulation: known as data hiding
access to data within an object is available only via the object's operation, known as interface of the object
2.polymorphism: different classes have different behaviors for the same operation.
polymorphism is more a characteristic of behaviors than it is of objects, only functions of a class can be polymorphic
3. inheritance: a subclass inherits attributes and operations from its superclass
if a sentence about 2 classes makes sense with "is a " relation, inheritance is probably appropriate
eg: a car is a vehicle, so car can inherit from vehicle
*/
class Vehicle
{
public $name; //do not omit modifier for attribute, can be accessed inside or outside class
public $speed = 10;
protected $price =100 ; //can be accessed inside class and subclass inherited from it
private $key =3; //can be accessed only within class
//A constructor is automatically called when a object is created, it is for initialization of setting sensible starting value
// public function __construct() //public modifier by default for function
//function __construct(){} ////no parameter by default,can be passed 0 or more thann one parameters
//function __construct($this->name) //wrong can not use this as a parameter
function __construct($name) //functions starting with __ change and set the value of any attributes that are inaccessible
{
echo "this is a $name"."<br>"; //$name is a new local variable to be passed in from outside , has nothing to do with $this->name
$this->name = $name; //to get value from outside class to initiate class name attribute
}
//setter will be invoked when something outside class access inaccessible variables, for encapsulation
//including protected, private and not declared variable,
// but public variable will not invoke the setter and getter, because we can access public variable
public function __set($property, $value)
{
if ($value > 100)
{
$current =$this->$property;
//notice: $this->property(without $) will create a new attribute called property, $property
$this->$property= $value;
echo "You are updating $property from $current to $value"."<br>";
}else{
echo "Update $property failed! the $property must be greater than 100"."<br>";
}
}
public function __get($property)
{
return "You are trying to get inaccessible $property 's value: " . $this->$property . " via getter <br>";
}
public function move() //by default
{
$this->start();
echo "$this->name is moving now"."<br>";
}
protected function openDoor() //can be used inside of inherited class, not outside subclass
{
echo "the door is openning now"."<br>";
}
private function start()
{
echo "$this->name is starting now"."<br>";
}
// A destructor is called automatically when all reference to the class have been unset or a a class is destroyed
//notice: it is the class that is destroyed, not the object of that class
function __destruct() //can not take parameters
{
// TODO: Implement __destruct() method.
}
}
//2. Instantiating Classes
$veh = new Vehicle('Bench'); //this is a Bench, 'Bench' will be passed to constructor and it is called automatically
//inside class using this pointer to access attributes and functions
//outside class using the reference to object to access attributes and functions
$veh->move();// Bench is moving now
echo $veh->name; //Bench
$veh->price = 20; //Update price failed! the price must be greater than 100, accessing protected variable, invoke setter
$veh->price = 120; //You are updating price from 100 to 120, accessing protected variable, invoke setter
echo $veh->price ;//You are trying to get inaccessible price 's value: 120 via getter
echo $veh->key; //You are trying to get inaccessible key 's value: 3 via getter
//3.Implementing inheritance
class Car extends Vehicle {
public $owner ='luoxu';
public function drive(){
echo "$this->owner is driving now <br>";
}
function toCallOpenDoor(){
$this->openDoor();
}
}
//as a subclass of Vehicle, Car has all the same functionality and data
//Car has declared an attribute and an operation of its own
//$carObj = new Car(); //constructor also inherit from Vehicle, must pass a parameter into otherwise wrong
$carObj = new Car("myCar");
echo 'calling public attribute :'.$carObj->speed."<br>";//10
echo 'calling protected attribute :'.$carObj->price; //You are trying to get inaccessible price 's value: 100 via getter
$carObj->price=334; //You are updating price from 100 to 334
echo 'after changing protected attribute :'. $carObj->price; //You are trying to get inaccessible price 's value: 334 via getter
echo 'calling its own public attribute :'.$carObj->owner."<br>"; //luoxu
$carObj->move();//myCar is starting now myCar is moving now
$carObj->drive(); //luoxu is driving now
//$carObj->openDoor(); //protected function can not be used outside subclass
$carObj->toCallOpenDoor(); //the door is openning now
echo ($carObj instanceof Car); //true
echo ($carObj instanceof Vehicle); //true
echo "<hr>";
//4. overriding function and variable
//preventing inheritance and overriding with final
class Person{
const HANDS=2;
public $name = "Joseph";
protected $age =24; //default value
public $pocket ="pocket money";
private $treasure ='Gold';
function read(){
echo "$this->name is reading CLASSIC book <br>";
echo "He is looking for $this->treasure and $this->pocket <br>";
}
final public function run(){
echo "Person runs at normal speed !";
}
public function showInfo(){
echo "$this->name has ".self::HANDS."hands";
}
}
class Kid extends Person{
public $age =8; //inherit protected variable $age, and overriding its default value
public function read() //overriding superclass's function read()
{ // :: can be used in static, const, overridden function
parent::read(); // we could call parent class's function by using keyword parent,
echo "He is $this->age years old <br>"; //overriding parent's methods
}//although parent::read() call the superclass method, php uses the attribute values from current class unless it is not overwritten
//luoxu is reading CLASSIC book //luoxu is from current(sub) class
//He is looking for Gold and pocket money //Gold and pocket money is from superclass because they are not provided in the current subclass
////He is 8 years old //8 is from current(sub) class
// public function run() //can not be overridden with final function
}
$k = new Kid();
$k->name = "luoxu"; //access attribute directLy from parent class
$k->read();
//5.Implementing Interfaces
//php doesn't support mulitiple inheritance, which means that each class can inherit from only one parent
//multiple inheritance can be confusing from a maintenance perspective, so various mechanism have been developed
// to exploit the advantages of multiple inheritance without paying maintenance cost.
//interface and trait are such mechanism
interface Eatable{
function eat();
}
interface Sleepable{
function sleep();
}
class Adult extends Person implements Eatable,Sleepable { //inherit from one class an multiple interfaces
public $name ="Adult person" ;
public function eat() //has to implement all function in the interface Eatable
{
// TODO: Implement eat() method.
echo "$this->name is eating ";
}
public function sleep() //has to implement all function in the interface Eatable
{
// TODO: Implement sleep() method.
}
}
$aObj = new Adult();
$aObj->eat(); //Adult person is eating
//6. Using traits
//th key difference between traitsand interfaces is that traits include an implementation, as opposed to merely
// specifying an interface that must be implemented
//Example 1
trait logger{
public function logMsg($message, $level ="DEBUG"){
echo "write $message to a logger in traits <br> ";
}
}
class file{
public function logMsg(){
echo "write $message to a file parent class parent class <br>";}
}
class fileStorage extends file{
use logger;
function store($data,$msg){
//……
$this->logMsg($msg); //calling function in traits
}
public function logMsg(){
echo "write $message to a file Storage current class <br>";}
}
$fs = new fileStorage();
$fs-> store('data','message to be showed!');
//if those functions have same name, priorities: current class function > traits function > parent function
//Example 2
//one nice thing about traits is that you can combine multiple traits which have methods with the same name
trait fileLogger{
public function logMsg($message, $level ="DEBUG"){
echo "write $message to a log file<br> ";
}
}
trait sysLogger{
public function logMsg($message, $level ="ERROR"){
echo "write $message to a syslog <br> ";
}
}
class loggerStorage{
use fileLogger, sysLogger{ //Trait method 'logMsg'in sysLogger collides with 'fileLogger'
//we should specify which one to use
fileLogger::logMsg insteadof sysLogger; //this line explicitly tells php to use logMsg() from fileLogger trait
sysLogger::logMsg as private logSysMsg; //rename logMsg in sysLogger, and also set visibility
//however, we also want to access logMsg() from sysLogger, we rename it using keyword 'as'
}
function store($msg){
//......
$this->logMsg($msg);
$this->logSysMsg($msg);
}
}
$ls = new loggerStorage();
$ls->logMsg('using method in trait like member method');
//$ls->logSysMsg(); private modifier ,inaccessible
$ls->store("message for storage");
//7. Display a large block of static HTML without processing with PHP
//you simply use an end php tag(? >), type your HTML, then re-enter php with an open php tag(<? php)
function displayHTML($size){
echo "codes below will show HTML codes to browser to display a table<br>";
?>
<!DOCTYPE HTML>
<html>
<body>
<table border="1">
<tr><td>this is a <?=$size?>block of static HTML tags </td></tr> //display variable value in html code
<tr><td>this is a <?=$size?> block of static HTML tags </td></tr>
<tr><td>this is a <?=$size?>block of static HTML tags </td></tr>
</table>
</body>
</html>
<?php
echo "html codes above";
}
displayHTML("large ");
//8.Advanced OOP Features
//1.using per-class consonant and static methods
class Math {
const PI =3.14; //this constant can be used without instantiate the class
static function area ($radius){
echo Math::PI; // way to access constant
echo self::PI; // way to access constant
return Math::PI * $radius *$radius;
//$this->PI don't use this because there may be no object instance to refer to
}
}
echo Math::PI; // way to access constant
echo Math::area(29); // way to access static function
//2. instanceof usage : echo ($carObj instanceof Car); //true
//type hint
function checkHint(Math $m, String $s,int $i,bool $b, array $a,callable $c){
//...... type hint for interface https://phpenthusiast.com/object-oriented-php-tutorials/type-hinting-for-interfaces
//type hint does not work for trait
}
// checkHint(new Math(),'string',1,true,[],displayHTML('large')); //type must match correspondingly
//3.late static bindings, late means call whichClass() a bit later for subclass B at runtime
class A{
public $name;
public $age;
public static function whichClass(){
echo __CLASS__;
}
public static function test(){
// self::whichClass(); //B::test() outputs A //because test() is executed in the context of the parent class A
static::whichClass(); //B::test() outputs B //static modifier makes php use class that was actually called at runtime
}
//This method will be invoked by a clone operator and will prepend "Copy " to the name and age properties.
public function __clone(){
// TODO: Implement __clone() method.
$this->name = "COPY".$this->name;
$this->age = "COPY".$this->age;
}
function __call($funName, $arguments)
{
echo "The function you called:" . $funName . "(parameter:" ; // Print the method's name that is not existed.
print_r($arguments); // Print the parameter list of the method that is not existed.
echo ")does not exist!!<br>\n";
}
}
class B extends A{
public static function whichClass(){
echo __CLASS__;
}
}
A::test(); //both are A
B::test();
//4.__clone is invoked by use of the clone keyword. It is used to manipulate object state upon cloning,
// after the object has been actually cloned
$a =new A();
$a->name ="Joseph";
$a->age =23;
$copyA = clone $a; // triggers the __clone magic method, $copyA is a second copy data, independent with $a
echo $copyA->name." ".$copyA->age; //COPYJoseph COPY23
$a->name ="luoxu";
$a->age =25;
echo $copyA->name." ".$copyA->age; //COPYJoseph COPY23
//5. Abstract class, which can not be instantiated, as well as abstract method
//to make sure every subclass contains or overrides some particular function
//this can be done with an interface
abstract class ClsAbstract{
abstract function test();
}
//6.__call()
$a->run("teacher",11);//The function you called:run(parameter:Array ( [0] => teacher [1] => 11 ) )does not exist!!
// If the method which is not existed is called within the object, then the __call() method will be called automatically.
//7.__autoload() check here https://www.tutorialdocs.com/article/16-php-magic-methods.html
//9. Iterator
//Using foreach to iterate through the attributes of an object
class myClass{
public $a= 1;
public $b= 2;
public $c= 3;
}
$x = new myClass();
foreach($x as $attribute ){
echo $attribute; //123
}
//get more info here https://www.startutorial.com/articles/view/modern-php-developer-iterator
class ArrIterator implements Iterator{ // implements Traversable
//Interface for external iterators or objects that can be iterated themselves internally
private $arr;
private $index;
private $length;
function __construct($obj){
$this->arr =$obj->data;
$this->length = count($obj->data);
}
/**
* @inheritDoc
*/
public function current() ////abstract method from iterator
{
// TODO: Implement current() method.
return $this->arr[$this->index];
}
public function next()
{
// TODO: Implement next() method.
$this->index++;
}
public function key()
{
// TODO: Implement key() method.
return $this->index ;
}
public function valid()
{
// TODO: Implement valid() method.
return $this->index < $this->length;
}
public function rewind()
{
// TODO: Implement rewind() method.
$this->index =0;
}
}
class ObjArr implements IteratorAggregate{ //// implements Traversable
/// //Interface to create and get an external Iterator.
public $data = array();
/**
* @inheritDoc
*/
function __construct($arr)
{
$this->data = $arr;
}
public function getIterator() ////abstract method from iterator
{
// TODO: Implement getIterator() method.
return new ArrIterator($this);
}
}
$oa = new ObjArr(array(3,4,5,5,6,77)); ////iterate array in a object-oriented mode
$iterator = $oa->getIterator();
for($iterator->rewind();$iterator->valid();$iterator->next()){
echo $iterator->key().'=>'.$iterator->current();
}
//10. Generator, check out more https://alanstorm.com/php-generators-from-scratch/
//the key difference between a generator and a function that fills a array with all possible values, is that it uses lazy execution
//Only one value is created and held in memory at any time, generator is helpful in large dataset that will not easily fit in memory.
//Generators are a special type of function in PHP that always returns a Generator object. Generator function
// definitions are similar to regular function definitions, with one exception.
// Instead of using a return keyword, they use a yield keyword.
// Generator implements Iterator {
// /* Methods */
// public current ( void ) : mixed
// public getReturn ( void ) : mixed
// public key ( void ) : mixed
// public next ( void ) : void
// public rewind ( void ) : void
// public send ( mixed $value ) : mixed
// public throw ( Throwable $exception ) : mixed
// public valid ( void ) : bool
// public __wakeup ( void ) : void
// }
function myGeneratorFunction()
{
yield;
}
$returnValue = myGeneratorFunction();
echo get_class($returnValue),"\n"; //Generator
//Although our function is defined with the regular old function keyword, PHP’s internals treat it differently
// because the function includes the yield keyword. PHP will always treat a function that includes the yield keyword
// as a generator function, and a generator function will always return a Generator object
$values = [1,2,3,4,5];
// using foreach
foreach($values as $number) {
echo $number, "\n";
}
// using an iterator
$iterator = new ArrayIterator($values); //Construct an ArrayIterator
while($number = $iterator->current()) {
echo $number, "\n";
$iterator->next();
}
///////////////////////////////////
# 1. Define a Generator Function
function generator_range($min, $max)
{
#3b. Start executing once `current`'s been called
for($i=$min;$i<=$max;$i++) {
echo "Starting Loop","\n";
yield $i; #3c. Return execution to the main program
#4b. Return execution to the main program again
#4a. Resume exection when `next is called
echo "Ending Loop","\n";
}
}
#2. Call the generator function
$generator = generator_range(1, 5); //create a generator object
#3a. Call the `current` method on the generator function
echo $generator->current(), "\n"; //call current function
#4a. Resume execution and call `next` on the generator object
$generator->next(); //execute the rest of loop with increment $i
#5 echo out value we yielded when calling `next` above
echo $generator->current(), "\n"; //
// give this a try when you have some free time
foreach(generator_range(1, 5) as $value) {
echo $value, "\n";
}
echo "<hr>";
//11.__toString() //if __toString() is not provided in the class, echo $person; will produces fatal error
class Doctor
{
public $sex;
public $name;
public $age;
public function __construct($name="", $age=25, $sex='Male')
{
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
public function __toString()
{
return var_export($this,true);
}
function showInfo(){
echo "Name $this->name";
}
}
$person = new Doctor('John'); // Initially assigned.
echo $person; // Doctor::__set_state(array( 'sex' => 'Male', 'name' => 'John', 'age' => 25, ))
//12. Using reflection API
$class = new ReflectionClass('Doctor'); //get basic info of unknown class
echo "<pre>".$class."<pre>";
echo "<hr>";
//13. Namespaces
//By default, all constant, class and function names are placed in a global space —
//like they were before namespaces were supported
//check here more https://www.sitepoint.com/php-53-namespaces-basics/
//14. Exception
try {
// do something, maybe throw some exceptions
} catch (Exception $e) {
// handle exception
} finally {
echo "Always runs!";
}
class myException extends Exception
{
function __toString() //overrides __toString() change the way it display error message
{
return "<strong>Exception ".$this->getCode()
."</strong>: ".$this->getMessage()."<br />"
."in ".$this->getFile()." on line ".$this->getLine()."<br/>";
}
}
try
{
throw new myException("A terrible error has occurred", 42);
}
catch (myException $m)
{
echo $m;
}
catch (Exception $e)
{
echo $e;
}