PHP学习(4)

本文是我边学PHP边写的学习研究,希望对于需要的人有所帮助。

PHP面向对象

基本使用:


date_default_timezone_set("PRC");

class NbaPlayer
{
    // 类的属性的定义
    public $name="Jordan";// 定义属性
    public $height="198cm";
    public $weight="98kg";
    public $team="Bull";
    public $playerNumber="23";

    // 默认的构造函数,在对象被实例化的时候自动调用
    /*function __construct() {
       print "In NbaPlayer constructor\n";
    }*/

    // 构造函数通常用于初始化对象的属性值
    function __construct($name, $height, $weight, $team, $playerNumber) {
        print $name . ";" . $height . ";" . $weight . ";" . $team . ";" . $playerNumber."\n";
       $this->name = $name; // $this是php里面的伪变量,表示对象自身
       $this->height = $height; // 通过$this可以设置对象的属性值
       $this->weight = $weight;
       $this->team = $team;
       $this->playerNumber = $playerNumber;
    }

    // 析构函数,用于清理程序中使用的系统资源,比如释放打开的文件等等
    // 析构函数在该对象不会再被使用的情况下自动调用
    function __destruct() {
       print "Destroying " . $this->name . "\n";
    }

    // 类的方法的定义
    public function run() {
        echo "Running\n";
    }

    public function jump(){
        echo "Jumping\n";
    }
    public function dribble(){
        echo "Dribbling\n";
    }
    public function shoot(){
        echo "Shooting\n";
    }
    public function dunk(){
        echo "Dunking\n";
    }
    public function pass(){
        echo "Passing\n";
    }
}

/**
 * 1. 类实例化为对象时使用new关键字,new之后紧跟类的名称和一对括号。
 * 2. 使用对象可以像使用其他值一样进行赋值操作
 */
$jordan = new NbaPlayer("Jordan", "198cm", "98kg", "Bull", "23");
// 访问对象的属性使用的语法是->符号,后面跟着属性的名称
echo $jordan->name."\n";
// 调用对象的某个方法使用的语法是->符号,后面跟着方法的名称和一对括号
$jordan->run();
$jordan->pass();

$james = new NbaPlayer("James", "203cm", "120kg", "Heat", "6");
echo $james->name."\n";
// 当对象变量被赋值为Null的时候,对象的析构函数会被自动调用
// 同一个类的其他对象不受影响
$james = null; 
echo "From now on James will not be used anymore.\n";
// 当程序执行结束时,所有类的对象的析构函数都会自动被调用
?>

引用:

// 当对象变量被赋值为Null的时候,对象的析构函数会被自动调用
// 同一个类的其他对象不受影响
$james1 = $james; // 引用赋值操作会产生对象的一个新的引用
$james2 = &$james; // 使用&的引用赋值操作不会产生对象的一个新的引用
$james = null; 

PHP学习(4)_第1张图片

继承:


date_default_timezone_set("PRC");
/**
 * 继承
 * 1. 定义人类
 * 2. 让NbaPlayer继承人类
 * 3. PHP中类不允许同时继承多个父类,也就是extends后面只能跟一个父类名称,这个特性被称为PHP的单继承特性
 */
class Human{
    public $name;
    public $height;
    public $weight;

    public function eat($food){
        echo $this->name . "'s eating ". $food. "\n";
    }
}

// extends关键字用于说明该类继承自某个父类
class NbaPlayer extends Human
{
    // 类的属性的定义
    public $team="Bull";
    public $playerNumber="23";

    private $age="40"; // private 类型的属性不能被对象外部访问,但是可以在对象内部使用

    // 默认的构造函数,在对象被实例化的时候自动调用
    /*function __construct() {
       print "In NbaPlayer constructor\n";
    }*/

    // 构造函数通常用于初始化对象的属性值
    function __construct($name, $height, $weight, $team, $playerNumber) {
        print $name . ";" . $height . ";" . $weight . ";" . $team . ";" . $playerNumber."\n";
       $this->name = $name; // $this是php里面的伪变量,表示对象自身
       $this->height = $height; // 通过$this可以设置对象的属性值
       $this->weight = $weight;
       $this->team = $team;
       $this->playerNumber = $playerNumber;
    }

    // 析构函数,用于清理程序中使用的系统资源,比如释放打开的文件等等
    // 析构函数在该对象不会再被使用的情况下自动调用
    function __destruct() {
       print "Destroying " . $this->name . "\n";
    }

    // 类的方法的定义
    public function run() {
        echo "Running\n";
    }

    public function jump(){
        echo "Jumping\n";
    }
    public function dribble(){
        echo "Dribbling\n";
    }
    public function shoot(){
        echo "Shooting\n";
    }
    public function dunk(){
        echo "Dunking\n";
    }
    public function pass(){
        echo "Passing\n";
    }
}

/**
 * 1. 类实例化为对象时使用new关键字,new之后紧跟类的名称和一对括号。
 * 2. 使用对象可以像使用其他值一样进行赋值操作
 */
$jordan = new NbaPlayer("Jordan", "198cm", "98kg", "Bull", "23");
// 访问对象的属性使用的语法是->符号,后面跟着属性的名称
echo $jordan->name."\n";
// 调用对象的某个方法使用的语法是->符号,后面跟着方法的名称和一对括号
$jordan->run();
$jordan->pass();
$jordan->eat("apple"); // 只要是Human类的子类的对象,就可以调用eat方法

?>

访问权限:
PHP学习(4)_第2张图片

 private $age="40"; // private 类型的属性不能被对象外部访问,但是可以在对象内部使用
 public function getAge(){
        echo $this->name . "'s age is " . ($this->age - 2) . "\n";
    }
 protected $height; // 只有自身和子类可以访问到

static关键字:

 public static $president="David Stern";

    public static function changePresident($newPrsdt){
        static::$president = $newPrsdt; // self用于表示当前类,"::"操作符用于访问类的静态成员
        // static关键字也可以用于访问当前类的静态成员
        // echo $this->age . "\n"; // 不能在静态方法中使用this伪变量,也不能用对象的->方式调用静态成员
        echo parent::$sValue . "\n"; // parent用于表示父类,可以用于访问父类的静态成员
    }
    // 类名加“::”可以访问类的静态成员
// 静态成员不需要实例化就可以访问
echo "The president is ". NbaPlayer::$president. "\n";
NbaPlayer::changePresident("Adam Silver");
echo "The president is changed to ". NbaPlayer::$president. "\n";

final关键字:

 
date_default_timezone_set("PRC");
/**
 * 重写和Final
 * 1. 子类中编写跟父类完全一致的方法可以完成对父类方法的重写
 * 2. 对于不想被任何类继承的类可以在class之前添加final关键字
 * 3. 对于不想被子类重写(overwrite, 修改)的方法,可以在方法定义前面添加final关键字
 */

class BaseClass {
   public function test() {
       echo "BaseClass::test() called\n";
   }

   public function moreTesting() {
       echo "BaseClass::moreTesting() called\n";
   }
}

class ChildClass extends BaseClass {

  // 重写时参数不一定要跟父类完全一致
   public function moreTesting($tmp=null) {
       echo "ChildClass::moreTesting() called\n";
   }
}
// Results in Fatal error: Cannot override final method BaseClass::moreTesting()
$obj = new ChildClass();
$obj->moreTesting();
?>

数据访问:


date_default_timezone_set("PRC");
/**
 * 数据访问补充
 * 1. parent关键字可以用于调用父类被重写的类成员
 * 2. self关键字可以用于访问类自身的成员方法,也可以用于访问自身的静态成员和类常量;不能用于访问类自身的属性;访问类常量时不用在常量名称前面加$符号
 * 3. static关键字用于访问类自身定义的静态成员,访问静态属性时需要在属性名前面添加$符号
 */

class BaseClass {
   public function test() {
       echo "BaseClass::test() called\n";
   }

   public function moreTesting() {
       echo "BaseClass::moreTesting() called\n";
   }
}

class ChildClass extends BaseClass {
  public $height="198cm";
  private static $sValue = "static value";
  const CONST_VALUE = 'A constant value';
  public function moreTesting() {
       echo "ChildClass::moreTesting() called\n";
       parent::moreTesting(); // parent关键字可以访问父类被重写的成员
       // step 3 self关键字可以访问该类自身的其他成员
       self::called();
       // step 4 self关键字可以访问该类定义的常量
       echo "CONST_VALUE: " . self::CONST_VALUE."\n";
       // 常量不能被赋值修改
       // self::CONST_VALUE = 11;
       // step 5 static关键字可以访问静态成员,当调用静态属性时记得加$符号
       echo "sValue: " . static::$sValue."\n";
  }
  // step 3
  public function called(){
    echo "ChildClass::called() called\n";
  }
 }
// Results in Fatal error: Cannot override final method BaseClass::moreTesting()
$obj = new ChildClass();
$obj->moreTesting();
?>

接口:


date_default_timezone_set("PRC");
/**
 * 接口
 * 1. 接口的基本概念和基本使用方法
 * 2. 接口里面的方法没有具体的实现
 * 3. 实现了某个接口的类必须提供接口中定义的方法
 * 4. 不能用接口创建对象,但是能够判断某个对象是否实现了某个接口
 * 5. 接口可以继承接口(interface extends interface)
 * 6. 接口中定义的所有方法都必须是公有,这是接口的特性。
 */

interface ICanEat {
   public function eat($food);
}

// Human类实现了ICanEat接口
class Human implements ICanEat { 
  // 跟Animal类的实现是不同的
  public function eat($food){
    echo "Human eating " . $food . "\n";
  }
}

// Animal类实现了ICanEat接口
class Animal implements ICanEat {
  public function eat($food){
    echo "Animal eating " . $food . "\n";
  }
}

// step1 不同的类可以实现同一个接口,定义接口方法的不同实现
$man = new Human();
$man->eat("Apple");
$monkey = new Animal();
$monkey->eat("Banana");

// step2 尝试删除Human的eat方法并运行
// 实现了某个接口的类必须提供接口中定义的方法

// step3 不能用接口创建对象,但是能够判断某个对象是否实现了某个接口
//$eatObj = new ICanEat();
var_dump($man instanceof ICanEat); // 判断某个对象是否实现了某个接口

// step 4 接口可以继承接口
interface ICanPee extends ICanEat {
  public function pee();
}

class Human1 implements ICanPee{
  public function pee(){}
}
?>

多态:


date_default_timezone_set("PRC");
/**
 * 多态
 * 1. 只要某个对象实现了接口(instanceof),就可以直接在对象上调用接口的方法
 */

interface ICanEat {
   public function eat($food);
}

// Human类实现了ICanEat接口
class Human implements ICanEat { 
  // 跟Animal类的实现是不同的
  public function eat($food){
    echo "Human eating " . $food . "\n";
  }
}

// Animal类实现了ICanEat接口
class Animal implements ICanEat {
  public function eat($food){
    echo "Animal eating " . $food . "\n";
  }
}

function eat($obj){
  if($obj instanceof ICanEat){ 
    $obj->eat("FOOD"); // 不需要知道到底是Human还是Animal,直接吃就行了
  }else{
    echo "Can't eat!\n";
  }
}

$man = new Human();
$monkey = new Animal();

// 同样的代码,传入接口的不同实现类的时候,表现不同。这就是为什么成为多态的原因。
eat($man);
eat($monkey);

?>

抽象类:


date_default_timezone_set("PRC");
/**
 * 抽象类
 * 1. 抽象类允许类里面的部分方法暂时没有具体实现,这些方法我们成为抽象方法
 * 2. 一旦类里面有抽象方法,这个类就必须是抽象类
 * 3. 抽象类跟接口一样,不能直接实例化为对象
 */

// 抽象类前面以abstract关键字开始
abstract class ACanEat {
   // 没有实现的方法需要设定为抽象方法
   // 抽象方法需要在子类中实现 
   abstract public function eat($food);

   public function breath(){
      echo "Breath use the air.\n";
   }
}

// Human类实现了ICanEat接口
class Human extends ACanEat { 
  // 跟Animal类的实现是不同的
  public function eat($food){
    echo "Human eating " . $food . "\n";
  }
}

// Animal类实现了ICanEat接口
class Animal extends ACanEat {
  public function eat($food){
    echo "Animal eating " . $food . "\n";
  }
}

$man = new Human();
$man->eat("Apple");
$man->breath(); // 和Animal共用了抽象类ICanEat的breath方法
$monkey = new Animal();
$monkey->eat("Banana");
$monkey->breath();

?>

魔术方法:


date_default_timezone_set("PRC");
/**
 * 魔术方法1
 * 1. 当对象被当做String使用时,__tostring()会被自动调用
 * 2. 当对象被当成方法调用时,__invoke()会被自动调用
 */
class MagicTest{
  public function __tostring(){
    return "This is the Class MagicTest.\n";
  }
  public function __invoke($x){
    echo "__invoke called with parameter " . $x . "\n";
  }
}

$obj =  new MagicTest();
echo $obj;
$obj(5);

?>

PHP学习(4)_第3张图片


date_default_timezone_set("PRC");
/**
 * 魔术方法2之方法重载
 * 1. 当对象访问不存在的方法名称时,__call()方法会被自动调用
 * 2. 当对象访问不存在的静态方法名称时,__callStatic()方法会被自动调用
 */
class MagicTest{
  public function __tostring(){
    return "This is the Class MagicTest.\n";
  }
  public function __invoke($x){
    echo "__invoke called with parameter " . $x . "\n";
  }
  public function __call($name, $arguments){
    echo "Calling " . $name . " with parameters: " . implode(', ', $arguments) . "\n";
  }

  public static function __callStatic($name, $arguments){
    echo "Static calling " . $name . " with parameters: " . implode(', ', $arguments) . "\n";
  }
}

$obj =  new MagicTest();
$obj->runTest("para1", "para2");
MagicTest::runTest("para3","para4");

?>

PHP学习(4)_第4张图片


date_default_timezone_set("PRC");
/**
 * 魔术方法3之属性重载
 * 1. 在给不可访问属性赋值时,__set() 会被调用。
 * 2. 读取不可访问属性的值时,__get() 会被调用。
 * 3. 当对不可访问属性调用 isset() 和empty()时,__isset() 会被调用。
 * 4. 当对不可访问属性调用 unset() 时,__unset() 会被调用
 */
class MagicTest{
  public function __tostring(){
    return "This is the Class MagicTest.\n";
  }
  public function __invoke($x){
    echo "__invoke called with parameter " . $x . "\n";
  }
  public function __call($name, $arguments){
    echo "Calling " . $name . " with parameters: " . implode(', ', $arguments) . "\n";
  }
  public static function __callStatic($name, $arguments){
    echo "Static calling " . $name . " with parameters: " . implode(', ', $arguments) . "\n";
  }
  // 通过这两个方法可以实现动态的对象属性
  public function __get($name){
    return "Getting the property " . $name;
  }
  public function __set($name, $value){
    echo "Setting the property " . $name . " to value ". $value. "\n";
  }

  public function __isset($name){
    echo "__isset invoked\n";
    return false;
  }

  public function __unset($name){
    echo "unsetting property " . $name;
  }
}

$obj =  new MagicTest();
echo $obj->name . "\n";
$obj->name = "Name Value";
echo '$obj->name is set? '. isset($obj->name) . "\n";
echo '$obj->name is empty?' . empty($obj->name) . "\n";
unset($obj->name);
?>

class nbaPlayer{
    public $name;
    function __clone(){
        $this->name='TBD';
    }
}
$james=new nbaPlayer();
$james2=clone $james;//没有__clone,james2是新的实例,但属性值相同;有了__clone,james2的$name值是'TBD'

你可能感兴趣的:(php)