# PHP 面向对象

软件工程的三个目标:重用性,灵活性,扩展性
特点: 封装,继承,多态

  • 类 【 大的类,人类
  • 对象 【具体的实体,new 类 产生对象
  • 面向对象的三个主要特征:
    • 对象的行为
    • 对象的状态
    • 对象的标识

# 如何抽象一个类

  • 类的声明
  • 成员属性
  • 成员方法

# 格式

[修饰符] class 类名 [extends 父类] [implements 接口1[,接口2...]] {
  [成员属性] // 成员变量
    // eg: public $name = "zhan";
    // --- 不可以是表达式,变量,方法或函数调用
    public $var1=1+2; // err
    public $var2=self::myStaticMethod(); // err
    public $var3=$myVar; // err
    public $var4= 100; // ok 普通数值(4个标量:整点、浮点、布尔、字符串
    public $var5= myContant; // ok 常量
    public $var6= self::classConstant; // ok 静态属性
    public $var7= arry(true, false);// ok 数组
  [成员方法] // 成员函数
    [修饰符] function 方法名(参数..){
      [方法体]
      [return 返回值]
    }
    public function say(){
      echo "人在说话";
    }
}

对象

$对象名称 = new 类名称();
$对象名称 = new 类名称([参数列表]);

对象中成员的访问

$引用名 = new 类名(构造参数);
$引用名->成员属性=赋值; // 对象属性赋值
echo $引用名->成员属性; // 输出对象的属性
$引用名->成员方法(参数); // 调用对象的方法

特殊对象引用$this

<?php
class Phone {
  public $width;
  public $height;
  public function play(){
    echo "正在玩手机!";
  }
  public function info(){
    $this->play();
    return "手机的宽度:{$this->width}, 手机的高度{$this->height}";
  }
}
$apple = new Phone();
$apple->width = 22;
$apple->height = 30;
$age = $apple->info();
echo $age;
?>

# 构造方法

[修饰符] function __construct([参数]){
  程序体;
}

# 析构方法

下面再也没有这个类调用的时候,用析构方法

[修饰符] function __destruct([参数]){
  程序体;
}
<?php
class Person {
  // 构造方法
  public function __construct($age){
    // 当这个类new的时候自动执行
    echo "hello $age";
    echo "<br/>";

    $this->age=$age;
  }
  public function data(){
    return $this->age;
  }
  // 析构方法
  public function __destruct(){
    // 可以进行资源的释放操作,数据库关闭
    // 对象被销毁的时候执行
    echo "bye {$this->age}";
    echo "<hr/>";

  }
}
$xiaoming = new Person("xiaoming");
$xiaohong = new Person("xiaohong");
echo $xiaoming->data();
$xiaoZhang = new Person("xiaoZhang");
?>

# 封装性

封装就是把对象中的成员属性和成员方法加上访问修饰符,使其尽可能的隐藏对象的内部细节,以达到对成员的访问控制【不是拒绝访问】。

  • 设置私有成员与私有成员的访问
  • __set()
  • __get()
  • __isset()
  • __unset()

# 修饰符

  • public 公有的,默认
  • private 私有的
  • protected 受保护的
class persion {
  public $name;
  private $age = 27;
  protected $money =100000;
  private function getMoney(){
    return $this->money;
  }
  protected function getAge(){
    return $this->age;
  }
  public function cardinfo(){
    return $this->getMoney().$this.getAge();
  }
}
$xiaoming = new persion();
echo $xiaoming->cardinfo();

封装后的成员在对象的外部不能直接访问,只能在对象的内部方法中使用$this访问

<?php
class person {
  public $aa;
  private $name;
  private $age = 27;
  protected $money =100000;
  private function getMoney(){
    return $this->money;
  }
  public function getAge(){
    return $this->age;
  }
  public function cardinfo(){
    return "Name: ".$this->name."<br/> Money: ".$this->getMoney()."<br/> Age:".$this->getAge();
  }
  public function setName($value){
    return $this->name = $value;
  }
  public function __set($key, $value){
    // echo "key:  ".$key."<br/>value: ".$value."<br/>";
    /// 魔术方法的set只针对protected或private
    if($key ==="name" && $value==="laowang"){
      $this->name = "xiaohai";
    }
  }
  public function __get($key){
    if($key === "age"){
      return "<br/>girl not tell you";
    }
  }
  public function __isset($key){
    if($key === "age"){
      return false;
    }
  }
}
try {
  $xiaoming = new person();
  $xiaoming -> name = "laowang";
  // echo $xiaoming->setName("laowang");
  // echo $xiaoming->cardinfo();
  // echo $xiaoming->age=2222;
  // echo $xiaoming->age;
  echo "<hr/>";

//   var_dump(isset($xiaoming->age));
//   echo isset($xiaoming->name)?"true":"false";
//   $xiaoming->aaa=3333;
//   echo $xiaoming -> aa;
//   unset($xiaoming->aaa);
//   echo "<hr/>";
//   echo $xiaoming -> aa."unset result";
//   echo "<hr/>";
//  echo $xiaoming->getAge();
 echo "<hr/>";
 echo "ssss";
} catch (Exception $e){
  echo $e->getMessage();
}
?>

# 继承

  • 类继承的应用
  • 访问类型的控制
  • 子类中重载父类的方法

# 访问权限

private protected public
同一类中 yes yes yes
在子类中 no yes yes
在类的外部 no no yes

# 子类中重载父类的方法

  • 在子类里允许重写(覆盖)父类中的方法
  • 在子类中,使用 parent 访问父类中被覆盖的属性和方法
parent::contruct();
parent::fun();
<?php
class Person{
  public $name;
  private $age;
  protected $money;
  public function __construct($name,$age,$money){
    echo 333;
    $this -> name= $name;
    $this -> age= $age;
    $this -> money= $money;
  }
  public function construct($name,$age,$money){
    echo 222;
    $this -> name= $name;
    $this -> age= $age;
    $this -> money= $money;
  }
  public function cardinfo(){
    echo "Name: ".$this->name."<br/> Money: ".$this->money."<br/> Age:".$this->age;
  }
  function __get($key){
    echo $key." is privated";
  }
}
class Woman extends Person{
  public function __construct($name,$age,$money){
    parent::construct($name,$age,$money);
  }
  public function cardinfo(){
    parent::cardinfo();
    echo "<br/>";
    echo $this->name;
    echo "<br/>";
    echo $this->money;
    echo "<br/>";
    echo $this->age;
  }
}
$s = new Person("小明", 22, 100000);
 $s -> cardinfo();
echo "<hr/>";
$sWm = new Woman("小明222", 2222, 100222000);
$sWm -> cardinfo();
echo "<hr/>";
echo $sWm->name;
echo "<hr/>";
echo $sWm->age;
echo "<hr/>";
echo $sWm->money;
?>

# 抽象类和接口

包含抽象方法的类叫抽象类
抽象类和抽象方法都是用abstract声明,如:

public abstract function fun();

# 抽象类的特点:

  • 不能实例化,也就是不能 new 成对象
  • 若想使用抽象类,就必须定义一个类去继承这个抽象类,并定义覆盖父类的抽象方法(实现抽象方法)

# 接口

接口:指定了一个实现了该接口的类必须实现一系列函数

// 定义格式:
interface 接口名称{
  // 常量成员(使用const关键字定义)
  // 抽象方法(不需要使用abstract关键字)
}
// 使用格式
class 类名 implements 接口名1,接口名2{
  ...
}

# 接口 和 抽象类

  • 当关注一个事物本质的时候,用抽象类,抽象类是对根源的抽象,表示这个类是什么,对类的整体进行抽象,对一类事物的抽象描述
  • 当关注一个操作的时候,用接口,接口是对动作的抽象,表示这个对象能做什么,对类的局部行为进行抽象

    男人和女人是两个类,他们的抽象类是人,人可以吃东西,狗也可以吃东西,然后 可以定义一个接口吃东西,然后让这些类去实现他

  • 所以一个类只能实现一个抽象类,但可以继承多个接口

# 区别

  • 接口是抽象类的变体,接口中所有的方法都是抽象的。而抽象类是声明方法的存在而不去实现他的类
  • 接口可以多继承,抽象类不行
  • 接口定义方法,不能实现,而 抽象类可以实现部分方法
  • 接口中基本数据类型为 statci,而抽象类不是
  • 接口中不能包含静态代码块及静态方法,而抽象类可以包含静态方法和静态代码块

# 对象的多态性

/**
* 1. 含义抽象方法的类必须是抽象类
* 2. 抽象类不一定非得有抽象方法
* 3. 抽象类不能被实例化,并由一个子类继承,并实现抽象类的抽象方法
*/
<?php
abstract class Person {
  public abstract function eat();
  public function dodo(){
    echo "dodo";
  }
}
class Man  extends Person {
  function eat(){
    echo "000";
  }
}
$man  = new Man();
$man->dodo();
$man->eat();
?>
<?php
// 1. 接口声明的关键字是interface
// 2. 接口可以声明常量也可以抽象方法
// 3. 接口中的方法都是抽象方法,不能用abstract去人肉的定义
// 4. 接口不能被实例化,需要一个类去实现它
// 5. 一个类不能继承多个类 一个类可以实现多个接口
interface Person {
  const NAME =  "xiaoming"; // 静态变量
  public function run();
  public function eat();
}
interface Study{
  public function study();
}
abstract class Human  implements Person,study {
  const data = 3.1415926;
  public function run(){
  }
  public function eat(){
  }
  public function study(){

  }
  public function test(){
    echo self::data;
  }
  public static function staticTest(){
    echo '<br/>'.self::data."-----22212311".'<hr/>';
  }
}
class Student extends Human {

}
$xw = new Student();
$xw->test();
$xw::staticTest();
echo $xw::NAME;
echo $xw::data;
?>

# 常见的关键字

  • final 关键字 只能修饰类和方法,不能使用 final 这个关键字来修饰成员属性
  • static 关键字
  • 单例设计模式
  • const 关键字
  • instanceof 关键字

# final 特征

  • 使用 final 关键字标识的类不能被继承
  • final 标识的方法不能被子类覆盖重写,是最终版本
  • -是位了安全
  • 二是没必要被继承和重写

# static

修饰静态属性和静态方法

# const

const 是在类中定义常量的关键字,

const CONTANT = 'constant value';
echo self::CONSTANT; // 类内部访问
echo className::CONTANT; // 类的外部访问

# instanceof

检测某一个是否是哪一个类

  • clss_exists
  • get_class_methods
  • get_class - 返回对象的类名
  • get_object_vars - 返回由对象属性组成的关联数组
  • string get_parent_class([ mixed $obj ]) - 返回对象或类的父类名
  • bool is_a(onject $object, string $class_name) - 如果对象属于该类或该类是此对象的父类则返回 TRUE
  • method_exists
  • property_exists

# PHP_系统自带的异常处理

class Exception {
  protected $message = "Unknown exception"; // 异常信息
  protected $code = 0; // 用户自定义异常代码
  protected $file;  // 发生异常的文件名
  protected $line;
  function __construct($message=null, $code=0);
  final function getMessage(); // 返回异常信息
  final function getCode();  // 返回异常的代码
  final function getFile();  // 返回发生异常的文件名
  final function getLine(); // 返回发生异常的代码行号
  final function getTrace(); // backtrace()数组
  final function getTraceAsString(); // 已格式化成字符串的getTrace信息
  function __toString(); // 可输出的字符串
}

# 继承系统错误类,自定义

<?php
class myException extends Exception {
  public function getAllInfo(){
    return "异常处理的文件为:{$this->getFile()},异常发生的行为为:{$this->getLine()}, 异常信息为{$this->getMessage()},异常代码为:{$this->getCode()}";
  }
 }
 try {
    if($_GET["num"] == 1){
      throw new myException("user");
    } else if($_GET["num"] == "2"){
      throw new myException("sys");
    }
    echo "success";
 } catch (myException $e){
   echo $e->getAllInfo();
 }
?>

# 一些魔术方法

  • __contract
  • __destruct
  • __call
  • __callStatic
  • __get
  • __set
  • __isset
  • __unset
  • __sleep
  • __wakeup
  • __toString
  • __set_state
  • __clone
  • __autoload

# __toString

<?php
class TestClass {
  public $foo;
  public function __construct($foo){
    $this->foo=$foo;
  }
  public function __toString(){
    return $this->foo." this is string";
  }
}
$class  = new TestClass("abc");
echo $class;  /// abc this is string
?>

# __clone()

class a

# 把对象串行化 seriallize()方法,**sleep()方法,**wekeup()方法

age=1&name=avb&agent=male =>{age: 1, name: "avb", agent: "male"}

# 应用场景
  • 在网络传输时,需要将对象串行化
  • 把对象写入文件或数据库的时候需要串行化
# 过程
  • 对象转为二进制,在使用时用 serialize()
  • __sleep 保留需要的量
  • __wakeup 重新生成对象时,重新给对象赋值
<?php
class Person{
  var $name;
  var $sex;
  var $age;
  function __construct($name="",$sex="", $age=""){
    $this->name = $name;
    $this->sex = $sex;
    $this->age = $age;
  }
  function say(){
    echo "我的名字是: ".$this->name.", 性别是:".$this->sex.", 我的年龄是: ".$this->age."<br/>";
  }
  function __sleep(){
    $arr = array("name", "age"); // 此时属性 $sex 将被删除
    return $arr;
  }
  function __wakeup(){
    $this->age = 40;
  }
}
$p1= new Person("张三","男", 20);
$p1_string = serialize($p1); // 把一个对象串行化,返回一个字符串
echo $p1_string."<br/>";
$p2 = unserialize($p1_string);
$p2->say();
?>

# __autoload()自动加载类

在使用未被定义的类时自动调用,脚本邀请在 PHP 出错失败前有一个最后的机会加载所需类,__autoload()函数就接收一个参数,就是想加载的类的类名

<?php
function __autoload($classname){
  require_once $classname.".php";
}
// MyClass1类不存在的时候,会自动调用 `__autoload()` 函数,传入参数"MyClass1"
$obj = new MyClass1();
// MyClass2类不存在的时候,会自动调用 `__autoload()` 函数,传入参数"MyClass2"
$obj = new MyClass2();
?>

# namespace 命名空间

<?php
namespace MyProject;
const CONNECT_OK = 1;
class Connection {/**/}

namespace AnotherProject;
const CONNECT_OK = 1;
class Connection {/**/}
?>

# js 里的面向对象

js 是面向原型链的语言
js 里没有 class, 可以用函数来创建类

function People(name) {
  // construct 会自动把内容执行掉
  this.name = name;
  console.log(this.name);
}
People.prototype.say = function(first_argument) {
  console.log(first_argument + " " + this.name);
};

// clone 功能
function Woman(name) {
  People.call(this, name);
}
var _prototype = Object.create(People.prototype);
_prototype.constructor = Woman;
Woman.prototype = _prototype;
Woman.prototype.run = function() {
  console.log(this.name + " is running");
};
var xiaohong = new Woman("kkk");
xiaohong.say("hi");
console.log(xiaohong);
xiaohong.run(); //error
var s = new People("ssss");
s.say("晚上好");
console.log(s);
s.run(); //error