目录

概念

本文是PHP对象的笔记,也论述了一些PHP面向对象实现上的得与失。

迟静态绑定

考虑下,子类的两个方法,都是用来实例化自身的,功能相同,只是类不同而已,能不能把它放入Father中,然后子类通过继承获取这种能力呢?

class Father{
    static function create(){
        return new self();
    }
}
class Son extends Father{ }
class Girl extends Father{ }

var_dump(Son::create()); // Object Father
var_dump(Girl::create()); // Object Father

self在类定义的时候,已经和该类绑定到一起了,即便子类继承了父类的create()函数,但是self()还是指向父类。所以PHP5.3之后,开发了迟静态绑定技术,使用static替代掉self,声明该处的代码,在实际执行的时候,根据它的执行者,来决定它所指向的类。

class Father{
    static function create(){
        return new static();
    }
}
class Son extends Father{
}
class Girl extends Father{
}

var_dump(Son::create()); // Object Son ,Son 执行的代码,所以 static 指向Son
var_dump(Girl::create()); // Object Girl

判断对象相等

== 只要两个对象属性一致就相等,===必须为同一个对象才相等。

对象克隆

$b = $a 直接赋值的其实是引用,$a$b指向同一个对象。
$b = clone $a; 是克隆一个$a对象,$a$b 分别指向不同的内存地址。

魔术方法 拦截器 overloader

class Test {
    public $params = [];
    public function __construct(){} // 当对象被创建时调用
    public function __destruct(){}  // 对象被销毁时调用

    // 当对象设置不存在的属性时,使用一个$params变量将设置的值保存起来
    public function __set($key,$value){$this->params[$key] = $value;}
    public function __get($key){return $this->params[$key];}

    //在对象调用不存在的方法时执行
    public function __call($func,$params){var_dump($func,$params);}
    static public function __callStatic($func,$params){} // 跟 __call 类似,给静态方法提供的
    public function __toString(){return __DIR__;}   // 把一个对象当做字符串使用时执行
    public function __invoke($params){}             // 当对象被当做一个函数使用时调用
    function __isset(){}        // 对不可访问或不存在的属性调用isset()或empty()时被调用
    function __unse(){}         // 对不可访问或不存在的属性进行unset时被调用
    function __sleep(){}        // 当使用serialize时被调用,当你不需要保存大对象的所有数据时很有用
    function __wakeup(){}       // 当使用unserialize时被调用,可用于做些对象的初始化操作
    function __clone(){}        // 进行对象clone时被调用,用来调整对象的克隆行为
    function __set_state(){}    // 当调用var_export()导出类时,此静态方法被调用
    function __debuginfo(){}    // 当调用var_dump()打印对象时被调用
}

命名空间

无命名空间的 php 代码都是在同一个空间下,不能有重名的类,和方法,属性。

__NAMESPACE__ 魔术常量,用于显示当前行所在命名空间

绝对命名空间 与 相对命名空间

namespace main; // 声明命名空间

// 相对命名空间 ,实际解析运行时,会在前面加上 main,即变成 main\com\geti...
com\getinstance\util\Debug::helloworld();

// 绝对命名空间,告诉PHP从根命名空间开始搜索
\com\getinstance\util\Debug::helloworld();

::class 获取类的完全限定名称

namespace NS;
    class ClassName {    }
    echo ClassName::class;  // NS\ClassName
abstract class Father{
    abstract public function say();
}
class Son1 extends Father{ public function say(){ echo "son1\n";}}
class Son2 extends Father{ public function say(){ echo "son2\n";}}
class Son_say{
    public function ask_son_say(Father $father){
        // 参数 ,我们使用的是抽象类,只要是该抽象类的子类,都有 say 方法,当然就有了各自的实现
        $father->say();
    }
}
$son1 = new Son1();
$son2 = new Son2();
$say  = new Son_say();
$say->ask_son_say($son1);
$say->ask_son_say($son2);

接口

1,是功能的封装抽象,我们只关注功能,不关心功能的实现,只要是继承了该接口的类,就应该具有接口的功能!
2,也就是说,你只要知道了一个对象的类型(继承了什么父类,实现了什么接口),就知道它能做什么!
3,接口和抽象类的区别在于:抽象类关注的是其子类的功能和共性的抽象,而接口更关注的是功能,实现该接口的类就需要有该功能,它不在意类的继承关系

interface Chargeable{ public function getPrice(); }
class ShopProduct implements Chargeable{
    public function getPrice(){
        return 5;
    }
}
class Test{
    // 这里限定类型是 接口,只要传递进来的类实现了该接口,都是合法的
    static public function echo_price(Chargeable $item){
        echo $item->getPrice();
    }
}
Test::echo_price(new ShopProduct());    // 5

对象语法参考

class Myclass{
    private $id = 0;//私有属性
    protected $name;
    const SUCCESS = "hehe";//类常量
    static private $instance=NULL;//静态变量
    public function __construct(){
        echo "构造方法";
    }
    public function __destruct(){
        echo "析构方法";
    }
    public function getId(){
        echo self::$instance; // 类内部使用静态变量
        return $this->id;
    }
    public static function hellostatic(){
        echo '这是类 的静态方法 ';
    }
    final function getBaseClassName(){
        echo "final修饰,这个方法不允许被子类重写";
        return __CLASS__; // 返回本类的类名
    }
}
$obj = new Myclass();
$obj_copy= clone $obj;      // 克隆一个新对象,有独立的内存地址
echo Myclass::SUCCESS;      // 直接使用类常量
Myclass::hellostatic();     // 直接使用静态方法
echo Myclass::$instance;    // 直接使用类静态变量
final class FinalClass(){
    function display(){
        echo 'final修饰,这个类是不允许被继承的';
    }
}
interface Display{
    function display(){}
}
class Circle implements Display{
    function display(){
        echo "我实现接口里面的方法";
    }
}
if($obj instanceof Myclass){
    echo "$obj 是类  Myclass 的实例";
}
abstract class MyBaseClass(){
    function display(){
        echo "抽象类禁止被实例化,只能被继承";
    }
    abstract function show(){} // 抽象类,没有任何功能,只能被继承
}

静态属性和静态方法

class StaticExample{
    static public $num = 10;
    public function func(){
        echo self::$num."static function ";     //在类内部使用 静态变量
    }
}
echo StaticExample::$num."\n";//在外部访问静态属性
StaticExample::func();//在外部调用静态方法

为何要使用静态变量和静态方法?

  • 在程序任意可以访问到类的地方都可以使用,不用为了获取一个简单的功能而实例化一个对象!

  • 由该类 new 出来的对象之间,可以共享一些东西!

  • 静态方法中,$this变量不允许使用。可以使用self,parent,static在内部调用静态方法与属性。

class Car {
    private static $speed = 10;
    public static function getSpeed() {
        return self::$speed;
    }
    public static function speedUp() {
        return self::$speed+=10;
    }
}
class BigCar extends Car {
    public static function start() {
        parent::speedUp();
    }
}
BigCar::start();
echo BigCar::getSpeed();

类的自动加载

spl_autoload_register("autoload1");
spl_autoloda_register("autoload2");

// 如果 new 操作未找到对应的类,就会执行注册好的自动加载函数
// $class 为带命名空间的类名
function autoload1( $class ) {
    require  __DIR__.$class.'.php';
}
function autoload2( $class ) {
    require  __DIR__.'/framework/'.$class.'.php';
}