PHP OOP
PHP 使用了一段时间, 从对OOP的不了解, 再到使用, 觉得挺好, 特写下
OOP并不是为了面向对象而面向对象, 而是为了达到代码的重用性、灵活性、扩展性
对象和类
从先有对象才有人类, 这个来说, 有点不合理的合理
类:具有相同属性的一组对象的集合
对象:类实例化之后就是对象
看下一般的类的定义
name = $name;
$this->age = $age;
$this->sex = $sex;
}
// 析构函数
function __destruct(){
echo "byebye\n";
}
// 成员方法
function eat(){
echo "my name is ". $this->name;
}
function sleep(){
echo "i am sleeping";
}
}
// 类的实例化
$jaime = new Person("jaime", "man", 24);
$jaime->eat();
?>
保存为index.php, 在命令窗口输入
$ php index.php
my name is jaime
byebye
如果
$jaime = new Person("jaime", "man", 24);
改为
$jaime = new Person("jaime", "man");
则会触发异常, 会有以下的消息出来, 包括错误信息, 错误行数, 和堆栈信息
$ php index.php
Fatal error: Uncaught exception 'Exception' with message 'must set name , sex, age' in E:\net\index.php on line 15
Exception: must set name , sex, age in E:\net\index.php on line 15
Call Stack:
0.0025 242440 1. {main}() E:\net\index.php:0
0.0025 243016 2. Person->__construct() E:\net\index.php:30
对象和内存
说点理论上的东西吧,
内存的分类:
堆(heap): 不可直接存取, 存储占有空间很大的数据类型的数据
栈(stack): 可以直接存取, 存储占用相同空间长度并且占用空间小的数据, 如存放局部变量,函数参数,当前状态,函数调用信息等
$jaime = new Person("jaime", "man", 24);
$jaime是存放在栈内存里面的引用变量, 即存储在堆中对象的首地址, 一个指针
new Person 实例化出来的对象是存放在堆内存里面的, 是真正的对象实例
对象和成员
变量,方法(内部成员函数)的前缀:
private: 私有成员
public: 公有成员(外部接口),没有加修饰, 默认就是public
protected: 保护型成员, 继承的类可以调用
访问private修饰的变量
Fatal error: Cannot access private property Person::$name in E:\net\index.php on line 36
如果想访问private, protected修饰的成员:
把private改为public
使用__get(), ___set()魔术方法, 但是还是写出代码来看看根据实际情况使用
name = $name;
$this->age = $age;
$this->sex = $sex;
}
function __destruct(){
echo "byebye\n";
}
function eat(){ echo "my name is ". $this->name."\n";}function sleep(){ echo "i am sleeping\n";}function __get($property_name){ $access_array = ['age','name'];// 只允许访问age,name两个私有成员 if(in_array($property_name, $access_array)){ return ($this->$property_name); } else{ return NULL; }}function __set($property_name, $value){ $access_array = ['age'];// 只允许访问age这个私有成员 if(in_array($property_name, $access_array)){ $this->$property_name = $value; }}
}
$jaime = new Person("jaime", "man", 24);
$jaime->eat();
echo ($jaime->age === NULL)? "NULL":$jaime->age;
echo "\n";
echo ($jaime->sex === NULL)? "NULL":$jaime->sex;
$jaime->age = 80;
echo "\n";
echo ($jaime->age === NULL)? "NULL":$jaime->age;
echo "\n";
$jaime->name = "lll";
echo ($jaime->name === NULL)? "NULL":$jaime->name;
echo "\n";
?>
执行结果如下
$ php index.php
my name is jaime
24
NULL
80
jaime
byebye
类的继承
name = $name;
$this->age = $age;
$this->sex = $sex;
}
function __destruct(){
echo "byebye\n";
}
function hello(){ echo "my name is ". $this->name."\n";}function sleep(){ echo "i am sleeping\n";}
}
class Student extends Person
{
private $school;
function __construct($name, $sex, $age, $school){ // 调用父类方法, 构造函数 parent::__construct($name, $sex, $age); $this->school = $school;}// 重载了父类方法function sleep(){ echo "afternoon sleep\n"; // 调用父类方法 parent::sleep();}
}
$jaime = new Student("jaime", "man", 24,"zh");
$jaime->hello();
$jaime->sleep();
?>
执行后输出
$ php index.php
my name is jaime
afternoon sleep
i am sleeping
byebye
调用父类的方法需要用parent
静态成员和常量
no bb, show code
show();
?>
结果
$ php is.php
China
en
I live in China
I live in American
xxxAmerican en
类的静态变量,类似于全局变量,能够被所有类的实例共享,类的静态方法也是一样的,类似于全局函数, 静态成员被这个类的每个实例对象所共享
访问静态方法访问静态成员不能用$this, 需要用self
$this表示了此方法的对象
'self'表示此静态方法所在的类, self::成员
抽象方法和抽象类
什么叫抽象?不具体的就叫抽象! so
抽象方法 : 类里面没有具体方法体的方法(其实就是不具体的方法)
抽象类: 含有抽象方法的类,
抽象类不能实例化会报错"Cannot instantiate abstract class ", 有点像C里面的函数声明, 仅仅只是一个声明
fun1();
(new demo0())->fun2();
(new demo0())->fun3();
?>
接口interface
什么是接口?
如果一个内里面所有的方法都是抽象方法, 我们可以把声明方式换为接口
接口是一种特殊的抽象类, 接口不能包含成员的任何代码,只定义成员身。接口成员的具体代码由实现接口的类提供
接口的继承
接口的实现
fun1();
(new demo())->fun2();
(new demo())->fun3();
(new demo())->fun4();
?>
一个类实现多个接口
一个人要遵守的法律不止一步吧, 所以see code
fun1();
(new demo())->fun2();
(new demo())->fun3();
(new demo())->fun4();
?>
你娶了你老婆你得对她的家人负责吧, 就像下面
// 使用extends继承一个类,使用implements实现多个接口
class demo extend AbstractClass implements One, Two{
......
// 所有接口中的方法都要实现才可以实例化对象
}
Trait
trait 是一种代码复用的方法, 同抽象类一样无法实例化
see code
word = $word;
}
public function sayHello() {
echo 'Hello '.$this->word."\n";
}
}
trait A {
public function sayHello() {
// 会调用继承基类中的方法
parent::sayHello();
}
}
trait B {
public function say(){
echo "this is a demo B";
}
}
class Demo extends Base {
// 使用use来引用trait
use A, B;
// 取消注释,当前类中的方法会覆盖trait方法,而trait方法又覆盖了基类中的方法
//public function sayHello(){echo "say hello";}
}
(new Demo('php'))->sayHello();
(new Demo('php'))->say();
?>
魔术方法
isset()/ unset()
isset() 检测变量是否设置,返回true/false
unset() 销毁指定的变量, 在销毁静态变量, 全局变量时要注意
__toString()
foo = $foo;
}
function toString(){
return $this->foo.FUNCTION__;
}
}
echo (new demo("jaime"));
?>
输出为
$ php ia.php
jaime__toString
__call()
调用不存在的方法就会自动调用__call()
test(1,2,3);
// 程序不会执行到这里
echo "go on";
?>
会报错
$ php ia.php
Fatal error: Call to undefined method demo::test() in E:\net\ia.php on line 5
Call Stack:
0.0000 235232 1. {main}() E:\net\ia.php:0
加上__call
test(1,2,3);
// 程序继续执行
echo "go on";
?>
结果
$ php ia.php
call function is test
Array
(
[0] => 1
[1] => 2
[2] => 3
)
not exist
go on
下面一段代码摘自ThinkPHP>controller.class.php
/ * 魔术方法 有不存在的操作的时候执行 * @access public * @param string $method 方法名 * @param array $args 参数 * @return mixed */public function __call($method,$args) { if( 0 === strcasecmp($method,ACTION_NAME.C('ACTION_SUFFIX'))) { if(method_exists($this,'_empty')) { // 如果定义了_empty操作 则调用 $this->_empty($method,$args); }else{ E(L('_ERROR_ACTION_').':'.ACTION_NAME); } }else{ E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); return; }}
__autoload()
它会在试图使用尚未被定义的类时自动调用,通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类
定义一个类,取名为Demo.class.php
再建立一个文件index.php
sayHello();
?>
很多的框架都利用这个函数实现 类文件的自动加载 ,下面是DiscuzX2.5的实现方式
__clone()
复制对象
serialize(), sleep(), wakeup()
对象序列化
参考:
《细说PHP 》 兄弟连
《PHP手册》
《php面向对象(OOP)编程完全教程》
关键字:php, oop
版权声明
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!