共计 4406 个字符,预计需要花费 12 分钟才能阅读完成。
最近在准备面试,复习了一下基础,包括 PHP 的类与对象。
1. 类是一种抽象定义,对象是一种实现。
# 定义类
class object
{
}
#实现类(对象)
new object
2. 类中包括属性与方法
访问控制(可见性)
class object
{
#可在内部调用,可被子类调用,可被外部(对象)调用
public $a;
#可在内部调用,可被子类调用
protected $b;
#可在内部调用
private $c;
}
3. 类的自动加载
类的自动加载,之前是使用__autoload(),现在,倾向于使用 spl_autoload_register() 注册器,实现懒加载
‘__’开头的为 php 中的语法糖
spl_autoload_register(function ($class){
echo $class;exit;
include $class . '.php';
});
new $a;
#输入
#a
4. 对象继承
继承一个类,就会继承父类的属性与方法(private 可见性除外),如果不覆盖父类的属性和方法,则会全部继承。
class parent_class
{
public $a;
public function func_a($arg)
{echo 'hello' . $arg;}
}
class son extends parent_class
{
}
$model = new son();
$model->func_a('liuser');
#输出
#hello liuser
# 重写子类
class son extends parent_class
{public function func_a($arg)
{echo '你好' . $arg;}
}
$model = new son();
$model->func_a('liuser');
#输出
#你好 liuser
#调用子类自己的属性
abstract class dbObject
{
const TABLE_NAME='undefined';
public static function GetAll()
{
# 这里使用 $c 或者 static 都可以
$c = get_called_class();
return "SELECT * FROM `".static::TABLE_NAME."`";
}
}
class dbPerson extends dbObject
{const TABLE_NAME='persons';}
class dbAdmin extends dbPerson
{const TABLE_NAME='admins';}
echo dbPerson::GetAll()."<br>";//output: "SELECT * FROM `persons`"
echo dbAdmin::GetAll()."<br>";//output: "SELECT * FROM `admins`"
5. 抽象类
抽象类用 abstract 表示,当一个类中有一个方法为抽象,则类必须被定义为抽象类,抽象类不能被实例化,只能被继承
抽象类中的方法只是定义其形式,不实现具体方法。
abstract class absclass
{#只能写方法名和参数,不能写具体实现(没有 {} 方法体)abstract protected function say($name);
abstract public function run();}
class class_1 extends absclass
{
#这里的可见性级别只能比父类更开发,protected 或者 public,不能使用 private
protected function say($name)
{// TODO: Implement say() method.
}
public function run()
{// TODO: Implement run() method.
}
}
6. 对象接口
接口 (interface), 规则类必须实现的方法,但不需要定义内容,同抽象类相似。
接口中定义的所有方法都必须是公有,这是接口的特性。
接口中的常亮不能被子类覆盖。
抽象中,只有抽象类中的抽象方法必须实现,接口中,只要定义为接口,就必须全部实现。
定义接口:interface
实现接口:implements
interface template
{public function setVariable($name, $var);
public function getHtml($template);
}
class template1 implements template
{public function setVariable($name, $var)
{// TODO: Implement setVariable() method.
}
public function getHtml($template)
{// TODO: Implement getHtml() method.
}
}
多重继承
interface a
{public function foo();
}
interface b
{public function bar();
}
interface c extends a, b
{public function baz();
}
class d implements c
{public function baz()
{// TODO: Implement baz() method.
}
public function bar()
{// TODO: Implement bar() method.
}
public function foo()
{// TODO: Implement foo() method.
}
}
7.trait(特性)
自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait, 说白了就是定义一个 trait, 然后在需要用到的类中使用 use 调用其。
特点:
1. 实现代码复用,解决多重继承问题。
2. 无法被实例化
想象一下,如果你需要在一个类中加上日志的相关方法,会怎么做呢?继承?如果有多个类都需要实现日志的方法呢?
如果需要继承,则违背了继承的原则,除非你的类是和日志相关。可以考虑使用特性解决。
trait log
{
#记录日志
public function start()
{echo time();
}
public function end()
{echo time();
}
}
class Car
{
#使用特性 log
use log;
}
$model = new Car();
$model->start();
$model->end();
使用 use 就是当 trait 中的方法复制到当前的类对象中,可能会产生问题。
比如 log 中定义了 start, 而 car 中也定义了 start,则会产生一个优先级的问题,官方给出的优先级如下:
优先顺序是当前类中的方法会覆盖 trait 方法,而 trait 方法又覆盖了基类中的方法。
9. 重载
动态的创建类方法或属性,使用魔法方法__set __get,注意一下用法。
1. 魔术方法的可见性必须是 public.
2. 如果类方法可类变量存在,则无法使用.
class test
{private $data = [];
public function __set($name, $value)
{$this->data[$name] = $value;
}
public function __get($name)
{if($this->data[$name]){return $this->data[$name];
}
echo '变量' . $name . '不存在';
}
}
$model = new test();
$model->name = 'liuser';
echo $model->name;
10. final
定义:如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。
这个很好了解,就不展开了,具体可以点开下面的链接
11.clone(克隆)
使用 clone 克隆一个对象,会把其进行浅复制。有一些特点
1. 因为是浅复制,所以对象的引用还是会指向对象之前的引用。
2. 如果对象定义了__clone 魔术方法,则在复制完成后会执行__clone
3. 如果类需要定义为单例模式时,则需要防止被克隆, 在__clone 方法写入 exit。
class c1
{
public $instance = 0;
public function __clone()
{$this->instance = $this->instance +1 ;}
public function say()
{echo 'hello';}
}
$m1 = new c1();
$m2 = clone $m1;
echo $m1->instance;
echo $m2->instance;
输出:0 1
12. 类型约束
在函数的参数执行参数所属的类型,包括对象、数组、接口
class c1
{public function say(){}}
class c2
{
#指定必须为 c1 的一个对象
public function f1(c1 $object)
{$object->say();
}
#指定必须为一个数组
public function f2(array $list)
{return $list['k1'];
}
#指定必须为一个回调函数
public function call(callable $call,$data)
{call_user_func($call,$data);
}
}
13. 对象与引用
PHP 的引用是别名,就是两个不同的变量名字指向相同的内容。在 PHP 5,一个对象变量已经不再保存整个对象的值。只是保存一个标识符来访问真正的对象内容。当对象作为参数传递,作为结果返回,或者赋值给另外一个变量,另外一个变量跟原来的不是引用的关系,只是他们都保存着同一个标识符的拷贝,这个标识符指向同一个对象的真正内容
class A {public $foo = 1;}
$a = new A;
# $a ,$b 都是同一个标识符的拷贝
$b = $a;
$b->foo = 2;
echo $a->foo."\n";
#结果等于 2
14. 序列化对象
所有 php 里面的值都可以使用函数 serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回 php 原来的值。序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
注意:如果反序列化,然后调用对象中的方法,则在之前,必须引入该类.
虽然在序列化的时候,不会保存对象的方法,但是在反序列化后,依然可以使用对象中的方法。
class A {
public $foo = 1;
public function say()
{echo 'hello';}
}
$a = new A();
$s_a = serialize($a);
#结果:O:1:"A":1:{s:3:"foo";i:1;}
$b = unserialize($s_a);
var_dump($b);
#object(A)#2 (1) {#["foo"]=>
# int(1)
#}
$b->say();
#结果 hello
echo $b->foo;
#结果 1