PHP教程学习07:PHP中的类与对象

学习教程来源于:
PHP中文网教程
PHP官网PHP手册(简体中文)链接

PHP面向对象编程(OOP)

OOP(面向对象编程)是一种编程思想,而不是技术

类与对象:
类是生成对象的模板
对象是类的一个实例

创建类
<?php  
// 1.类名必须符合标识符定义
//推荐使用帕斯卡命名法,标识符的第一个首字母大写
class Demo 
{
	//属性和方法
	//属性的声明必须以访问控制符开头
	public $name = 'php';	//公共属性,外部可以访问
	//属性访问控制符:public/private/peotected
	private $age = 20;	//私有属性,只允许类中的访问调用
	protected $sex = 'male';//受保护的,仅允许本类或者子类访问
	// 属性类型支持:标量(整数、浮点、字符串、布尔值),复合类型和对象

	// 方法也必须以访问控制符开头:public/private/protected
	public function getName()
	{
		//$this是伪变量,总是指向当前对象
		return  $this->name;
	}
	public function getAge()
	{
		return $this->age;
	}
}

// 创建对象的过程就是类的实例化
$obj = new Demo();	//	$obj 就是类Demo的实例
//类必须实例化才可以访问里面的属性和方法
echo $obj->name;	//用对象访问符来直接访问属性
echo '<br/>';
echo $obj->getName();
// echo $obj->age;		//private定义的属性不能在外部访问
echo '<br/>';
echo $obj->getAge();
//对象是一个引用变量,我们对对象的赋值并没有创建新的对象,而是创建一个对当前对象的引用
$obj2 = $obj;  //并没有创建新对象
if ($obj2 = $obj;) {
	echo '相等';
} else {
	echo '不相等';
}

echo '<br/>';
echo get_class($obj2);
echo '<br/>';
echo get_class($obj);
echo $obj2->name;
echo $obj->name;
//如果在类的外部访问属性或方法,可以直接用对象
//如果在类的内部访问属性或方法,必须使用伪变量$this

创建对象的六种方法
<?php  
class Demo1
{
	public $name = 'php中文网';
	public function getName()
	{
		return $this->name;
	}
	public function getObj()
	{
		return new self();
	}
	public function getStatic()
	{
		return new static();
	}
}
//关键词 extends 继承
class Demo2 extends Demo1 
{
	public function getNewObj()
	{
		return new parent();
	}
}

1.用new 类名()来创建一个对象

$obj = new Demo1();//如果不需要传入参数,可以省略括号
echo $obj->name;
echo '<hr/>';

2.将类名一字符串的方式放在一个变量中

$className = 'Demo1';
$obj1 = new $className();
echo $obj1->name;
echo '<hr/>';

3.用对象来创建对象,并且他创建的是一个新对象

$obj2 = new $obj();  //注意:$obj2 = $obj 不同
// echo get_class($obj2);
echo $obj2->name;
echo '<hr/>';

4.用new self()

$obj3 = $obj->getObj();
// echo get_class($obj);
echo $obj3->name;
echo '<hr/>';

5.用new parent() 来创建一个对象

$obj4 = (new Demo2)->getNewObj();
// echo get_class($obj4);
echo $obj4->name;
echo '<hr/>';

6.基于当前调用的类来创建:new static()

$obj5 = (new Demo1)->getStatic();
$obj6 = (new Demo1)->getObj();
echo get_class($obj5);
echo get_class($obj6);
echo '<hr/>';

$obj7 = (new Demo2)->getStatic();
$obj8 = (new Demo2)->getObj();
echo get_class($obj7);	//new static()
echo get_class($obj8);	//new self()
// new static()方式创建的对象直接与调用者绑定,静态延迟绑定
类常量
<?php

class Demo 
{
	// 类常量就是它的值在类中始终不变的量
	// 类常量是用const关键字创建,不要加$,必须初始化
	const siteName = 'php中文网';
	// 类常量从php5.3开始支持nowdoc语法
	const domain = <<< 'EOT'
<a href="">www.php.net</a>
//此处结束标签一定要在第一列
EOT;
	public function getSiteName()
	{
		//在类的方法中访问类常量:self::内场了名
		return self::siteName;
	}
}

//方法1:类名::类常量名
echo '1.类名::类常量名:'.Demo::siteName.Demo::domain.'<hr/>';

//方法2:类变量::类常量名 php5.3+
$className = 'Demo';
echo '2.类变量::类常量名:'.$className::siteName.'<hr/>';

//方法3:用当前类的对象来访问类常量
echo '3.对象::类常量名:'.(new Demo)::siteName.'<hr/>';

//方法4:用类中的方法来间接访问类常量
echo '4.对象->方法():'.(new Demo)->getSiteName();
类的自动加载技术
<?php
//1.用require导入一个类文件
// require('test.php');//导入test.php
// include('test.php');

//2.__autoload()当我们引入一个不存在的类时,自动调用它导入该类文件
// 此方法php7.2+已弃用
// This feature has been DEPRECATED as of PHP 7.2.0. Relying on this feature is highly discouraged.
function __autoload($className)
{
	$path = $className.'.php';//Test.php
	if (file_exists($path)) {
		require_once($path);
	} else {
		echo $path.'不存在,请检查~~';
	}
}


3.自定义导入函数,用spl_autooad_register()将自定义的类导入函数添加到函数栈中
function loader($className)
{
	$path = $className.'.php';//Test.php
	if (file_exists($path)) {
		require_once($path);
	} else {
		echo $path.'不存在,请检查~~';
	}
}
spl_autoload_register('loader');
echo (new Test('我爱php'))->name;

将自定义的导入函数放到一个类的方法里
class LoaderClass
{
	function loader($className)
	{
		$path = $className.'.php';//Test.php
		if (file_exists($path)) {
			require_once($path);
		} else {
			echo $path.'不存在,请检查~~';
		}
	}

}
// 当自定义的函数为类中的方法时,需要放入数组中
// spl_autoload_register(['类名/对象(调用者)','方法名']);
spl_autoload_register([(new LoaderClass),'loader']);
echo (new Test('欢迎来到php中文网学习~~'))->name;

// 静态方法
class LoaderClass
{
	static function loader($className)
	{
		$path = $className.'.php';//Test.php
		if (file_exists($path)) {
			require_once($path);
		} else {
			echo $path.'不存在,请检查~~';
		}
	}

}
spl_autoload_register(['LoaderClass','loader']);
echo (new Test('欢迎来到php中文网~~'))->name;

类的构造方法与析构方法
<?php
// 构造方法:用来实例化类,创建对象的
class Staff 
{
	public $name;
	public $age;
	public $salary;
	//构造方法使用固定的方法名:__construct()
	public function __construct($name,$age,$salary)
	{
		// 构造方法:通常用来初始化对象中的属性
		$this->name = $name;
		$this->age = $age;
		$this->salary = $salary;
	}
	// 析构方法对象销毁时调用,没有参数,__destruct()
	public function __destruct()
	{
		echo '当前对象被销毁了~~';
	}
}

// 创建一个对象,来访问类中的属性
$obj = new Staff('Peter', 28, 3500);
echo '姓名:'.$obj->name;
echo '<hr/>';
echo '年龄:'.$obj->age;
echo '<hr/>';
echo '薪水'.$obj->salary;
echo '<hr/>';

//销毁变量,使用unset()方法
unset($obj);
对象的封装
<?php
// 对象的封装,主要是指对象属性的封装,同private访问控制符
class Staff
{
	private $name; 
	private $age;
	private $salary;
	public function __construct($name,$age,$salary)
	{
		$this->name = $name;
		$this->age = $age;
		$this->salary = $salary;
	}
	public function __get($name)
	{
		return $this->$name;
	}
	public function __set($name,$value)
	{
		if ($name == 'age') {
			return false;
		}
		$this->$name = $value;
	}
	// __isset():检测是否存在某个属性
	public function __isset($name)
	{
		return isset($this->$name);
	}
	// __unset(属性名):在类外部销毁某个私有属性时自动调用它
	public function __unset($name)
	{
		unset($this->$name);
	}
}

$obj = new Staff('Peter', 28, 4500);
echo $obj->name;
echo $obj->age;
echo $obj->salary;
echo '<hr/>';
$obj->name = 'Tom';
echo $obj->name;
echo '<hr/>';
$obj->age = 68;
echo $obj->age; 
echo '<hr/>';
$obj->salary = 7900;
echo $obj->salary; 
echo '<hr/>';
// 为什么上面的$obj->name可以检测到值,isset里面的就不行呢?
echo(isset($obj->name))?'存在':'不存在';
echo '<hr/>';
// unset($obj->age);
// echo $obj->age;
类的继承与多态
<?php
// 继承可以实现代码复用,构建类的等级关系
// 类Person,作为父类
class Person
{
	protected $name;//protected受保护的,外部不可访问,只允许自己内部或子类访问
	protected $age;
	protected $salary;
	// 创建构造方法,用来实例化这个类
	public function __construct($name,$age,$salary)
	{
		$this->name = $name;
		$this->age = $age;
		$this->salary = $salary;
	}
	// 申明为收保护的,这样就只能被子类继承,子类继承过去仍然是protected
	protected function showMess()
	// public function showMess()
	{
		return '我的姓名是'.$this->name.',年龄是:'.$this->age.',工资是:'.$this->salary;
	}
}
// 声明一个子类(扩展类),继承使用关键字:extends,php是单继承语言
// 创建子类是为了扩展父类的功能,实现代码复用
class Staff extends Person
{
	protected $department;//员工所在的部门
	public function __construct($name,$age,$salary,$department)
	{
		// 继承父类属性
		parent::__construct($name,$age,$salary);
		$this->department = $department;
	}
	// 在子类中重写父类方法时,其访问权限不能低于原来的,原来是protected,那么现在就应该是public(访问权限:public>protected>pravited)
	public function showMess()
	{
		return parent::showMess().',部门是:'.$this->department;
	}
}

$obj = new Staff('小明',23,1500,'开发部');
echo $obj->showMess();

// 多态,全称为多种状态,与方法重载非常类似,可以根据传入参数不同,提供不同的服务, php不支持多继承,不过,php5.4+提供了trait技术,类似于在当前类中插入一个外部方法集,实现了部分多继承功能
// 多态是通过对父类中的方法进行重写实现,在子类中定义一个与父类同名的方法就会对其进行重写
类中静态成员的创建与访问技巧
<?php
class Father
{
	//访问控制符:指示类成员在哪里可以被访问:public/private/protected
	//成员状态符:指示如何访问该成员:静态self/parent/static 非静态:$this->
	public static $name = 'peter';	//公共静态属性,类内部/外部/子类均可访问
	private static $age = 28;		//私有静态属性,只能在类内部访问
	protected static $salary = 3600;//受保护的静态属性,可以在类内部和子类中访问
	public static function show () //静态方法
	{
		//非静态方法可以调用静态方法,静态方法不可以调用非静态方法!
		return '年龄:'.self::$age.'---'.'工资'.self::$salary;
	}
}
// 创建子类Son,继承自Father类
class Son extends Father
{
	public static function display()
	{
		//parent::引用父类中的静态成员
		return '工资是:'.parent::$salary;
	}
}
echo '姓名是:'.Father::$name;//外部访问静态成员,使用类名::静态成员,静态属性必须加$符号
//静态成员:静态属性和静态方法
echo '<hr/>';
echo Father::show();//访问类中的静态方法
echo '<hr/>';
echo Son::show();	//用子类访问父类中的静态方法
echo '<hr/>';
echo Son::display();//访问子类的静态方法
echo '<hr/>';
$obj = new Father;
echo $obj->show();	//外部使用对象,也可以访问静态方法
// echo $obj->name;	//外部对象不能访问类中的静态属性
echo '<hr/>';
$res = $obj instanceof Father;
echo '$obj是Father类的实例吗?'.($res?'是的':'不是的');
类的静态绑定与延迟绑定技术
<?php
class Demo1 
{
	public static $name = 'peter';
	public static $salary = 3000;
	public static function show()
	{	//self::与Demo1类静态绑定
		// return self::$name;//访问本类中的静态属性self::就是当前类
		// return static::$name;//访问本类中的静态属性static::就是当前类
		return static::$sex;//static 与self,parent是不一样的,它对应的类是动态设置的,由调用类决定,如果说self和parent是静态绑定的话,static就是动态绑定到类,叫做静态延迟绑定(后期静态绑定)
		// 静态绑定(self和parent)它们与类的绑定在代码的编译阶段进行,
		//而static与类的绑定实在代码的运行时才进行绑定,所以叫做:静态延迟绑定(与类的绑定机制不同)
		//static 谁调用它,就和谁绑定
	}
}

class Demo2 extends Demo1 
{
	public static $sex = 'male';
	public static function display()
	{
		//parent::与父类进行绑定,self::与Demo2类静态绑定
		// return parent::$name.'的工资是:'.parent::$salary.' 性别是:'.self::$sex;
		//parent::与父类进行绑定,static::与Demo2类静态绑定
		return parent::$name.'的工资是:'.parent::$salary.' 性别是:'.static::$sex;
	}
}
// echo '姓名是:'.Demo1::$name;//在外部访问类中的静态属性
// echo '<hr/>';
// echo '姓名是:'.Demo1::show();//在外部访问类中的静态方法
// echo '<hr/>';
// echo Demo2::display();
echo '性别是:'.Demo2::show();
对象的克隆技术
<?php
class Demo
{
	public $name = 'peter';
}
$obj1 = new Demo;
$obj2 = $obj1;	//对象都是引用赋值
$obj3 = clone $obj1; //克隆,相当于值传递赋值,将当前对象复制到新的变量中
$obj4 = new Demo;
$obj1->name = 'Jack';//重新设置对象$obj1中的属性name的值
echo '对象引用:'.$obj1->name,'---',$obj2->name;
echo '<hr/>';
echo '克隆赋值:'.$obj1->name,'---'.$obj3->name;
echo '<hr/>';
echo '创建对象:'.$obj1->name,'---'.$obj4->name;
echo '<hr/>';
echo '克隆对象的类是:'.get_class($obj3);
// 克隆就是将当前对象复制一份镜像,与重新new一个对象完全相同
// 对象赋值是引用,仅仅是给当前对象起一个别名,并没有创建新对象
// 关键字clone克隆出的一个与原来对象毫无关系的新对象
访问不存在的方法或不存在的静态方法
<?php
class Demo
{
	//第一个参数是方法名,第二个参数是方法参数,以数组形式传入
	public function __call($method,$argus)
	{
		// 遍历参数argus
		$var = '';
		foreach ($argus as $value) {
			$var .= $value.',';//.= 字符串连接运算
		}
		return '方法是'.$method.'('.$var.')'.'不存在';
	}
	//当我们调用一个不存在的静态方法时,会自动调用__callStatic()
	public static function __callStatic($method,$argus)
	{
		// 遍历参数argus
		$var = '';
		foreach ($argus as $value) {
			$var .= $value.',';//.= 字符串连接运算
		}
		return '静态方法是'.$method.'('.$var.')'.'不存在';
	}
}
// 当访问一个不存在的静态方法是,自动调用类中的魔术方法:__call()
echo (new Demo)->hello('php','python');
echo '<hr/>';
// 当访问一个不存在的静态方法是,自动调用类中的魔术方法:__callStatic()
echo Demo::hello(10,20,30);
对象的序列化
<?php
class Staff
{
	public $name;
	public $age;
	public $salary;
	public function __construct($name,$age,$salary=0)
	{
		$this->name = $name;
		$this->age = $age;
		$this->salary = $salary;
	}
	public function __sleep()
	{
		//将允许序列化的对象属性放在一个数组中返回
		return ['name','age'];
	}
	public function __wakeup()
	{
		$this->age = 48;
	}
}
$obj1 = new Staff('peter',28,5000);
// 序列化之前对象属性
echo '我的姓名是:'.$obj1->name,'年龄是:'.$obj1->age,'工资是:'.$obj1->salary;
echo '<hr/>';
$objStr = serialize($obj1);
echo '序列化的对象:'.$objStr;
echo '<hr/>';

// 反序列化
$obj2 = unserialize($objStr);
echo '我的姓名是:'.$obj2->name,'年龄是:'.$obj2->age;

抽象方法与抽象类
<?php
// 抽象类不能单独使用,不能被实例化,只能通过子类进行调用。可以看做子类的一个模板。

// 当一个类中有有抽象方法时,它就需要被声明为抽象类
abstract class Demo
{
	public $name;
	public function __construct($name)
	{
		$this->name = $name;
	}
	abstract public function hello();
	abstract public function say();
	public function test()
	{
		return 'Demo::test()';
	}
}

// 抽象方法必须被一个子类继承,才能使用

class Demo1 extends Demo
{
	// 必须在子类中加工抽象类中的全部抽象方法实现才可以
	public function hello()
	{
		return 'hello'.$this->name;
	}
	public function say()
	{
		return '我的name是:'.$this->name;
	}
} 

$obj = new Demo1('php');
echo $obj->hello();
echo '<hr/>';
echo $obj->say();
echo '<hr/>';
echo $obj->test();

// 抽象类只是规范了子类要有父类中声明的抽象方法,具体的实现是由子类决定的


接口技术的实现
<?php
// 接口的访问控制符必须是public
// 接口1:Demo1
interface Demo1
{
	// 接口成员属性必须是:类常量
	const SITENAME = 'PHP中文网';
	// 接口成员的方法必须是抽象方法,而且访问控制符必须是public,abstract也可以省略
	function show();
	function mess();
}
// 接口2:Demo2
interface Demo2
{
	function hello();
}
// 接口不允许实例化,但可以被继承,所以需要创建一个类,来继承接口,并实现接口中全部抽象方法

class Test implements Demo1,Demo2
{
	// 实现接口Demo1中的show()方法
	public function show()
	{
		return '站点名称是:'.self::SITENAME;
	}
	// 实现接口Demo1中的mess()方法
	public function mess()
	{
		return '站点域名是:www.php.cn';
	}
	// 实现接口Demo2中的hello()方法
	public function hello()
	{
		return self::SITENAME.'欢迎您~~';
	}
}

$obj = new Test;
echo $obj->show();//访问接口Demo1中的show()方法
echo '<hr/>';
echo $obj->mess();//访问接口Demo1中的mess()方法
echo '<hr/>';
echo $obj->hello();//访问接口Demo2中的hello()方法
echo '<hr/>';

trait特性的声明和使用技巧
创建一个trait类Test1
trait Test1
{
	public $name = 'PHP中文网';//trait类中可以有属性,不能有类常量
	public function hello1()
	{
		return 'Test::hello1()';
	}
}

// 2.创建一个trait内Test2
trait Test2
{
	use Test1;
	public function hello2()
	{
		return 'Test2::hello2()'.$this->name;
	}
}
// 3.创建父类
class Demo
{
	public function hello2()
	{
		return '父类Demo::hello2()'.$this->name;
	}
}
// 4.创建类Demo1
class Demo1 extends Demo
{
	use Test2;
	// 同一类中,同名方法的访问优先级:子类>trait类>父类
	public function hello2()
	{
		return '子类Demo1::hello2()'.$this->name;
	}
}

// 测试
$obj = new Demo1;
echo $obj->hello1();//访问trait类Test1中的hello1()
echo '<hr/>';
echo $obj->name;	//访问呢trait类Test1中的属性
echo '<hr/>';
echo $obj->hello2();


trait Test1
{
	public function hello()
	{
		return 'Test1::hello()';
	}
}

trait Test2
{
	public function hello()
	{
		return 'Test2::hello()';
	}
}

class Demo
{
	use Test1,Test2{
	  // 用Test1:hello()替代Test2::hello()
	  Test1::hello insteadof Test2;
	  // 用别名访问Test2::hello()方法
	  Test2::hello as test2Hello;
	}
}
// 测试
$obj =  new Demo;
echo $obj->hello();
echo '<hr/>';
echo $obj->test2Hello();//test2Hello 是Test2::hello()方法的别名
命名空间
<?php
namespace test1;
const SITE_NAME = 'php中文网';//声明常量SITE_NAME
function sum($n, $m)//声明函数sum()
{
	return $n+$m;
}

class Staff
{
	private $name = 'peter';
	public function __get($name)
	{
		return $this->$name;
	}
	public function __set($name,$value)
	{
		return $this->$name = $value;
	}
}

namespace test2;
// use test1;	//只定位到空间 并不定位到类
use test1\Staff as test1Staff;	//定义到空间中的类
use test2\test3\Demo;
const SITE_NAME = 'www.php.cn';//声明常量SITE_NAME
function sum($n, $m)//声明函数sum()
{
	return $n+$m;
}

class Staff
{
	private $name = 'jack';
	public function __get($name)
	{
		return $this->$name;
	}
	public function __set($name,$value)
	{
		return $this->$name = $value;
	}
}

//访问
echo '当前的命名空间:'.__NAMESPACE__;
echo '<hr/>';
echo SITE_NAME;//非限定名称的命名空间
echo '<hr/>';
echo \test1\SITE_NAME;//完全限定名称的命名空间
echo '<hr/>';
echo sum(10, 20);
echo '<hr/>';
$obj = new Staff;
echo $obj->name;
echo '<hr/>';
$obj1 = new Staff;
$obj1->name = 'Tom';
echo $obj1->name;
echo '<hr/>';
echo Demo::CITY;

/*
代码的命名空间分为俩类:
1.全局空间(公共空间):其中的类、常量、函数都是全局成员,不允许重名
2.可命名空间:可以重名,不冲突

实际开发中一个文件用一个命名空间
*/

namespace test2\test3;
class Demo
{
	const CITY = '合肥';
}
对象的遍历
<?php
class Demo
{
	public $name;
	public $age;
	public $salary;
	private $sex;
	protected $isMarried;
	//静态属性不属于对象,属于类
	public static $home;
	// 声明构造方法,用来初始化对象
	public function __construct($name,$age,$salary,$sex,$isMarried,$home)
	{
		$this->name = $name;
		$this->age = $age;
		$this->salary = $salary;
		$this->sex = $sex;
		$this->isMarried = $isMarried;
		self::$home = $home;
	}
	// 声明一个query方法,用来在类的内部遍历属性
	public function query()
	{
			print '遍历出对象的全部属性,包括私有和受保护的:<br/>';
			foreach ($this as $key => $value){
				echo $key.'=>'.$value.'<br/>';
			}
			print self::$home;
	}
}
// 外部访问
$obj = new Demo('peter', 28, 3800, 'male', true, '合肥');
// 遍历对象
echo '外部访问的公共属性:<br/>';
foreach ($obj as $key => $value){
	echo $key.'=>'.$value.'<br/>';
}
echo Demo::$home;//外部使用类名访问静态成员;
echo '<hr/>';
$obj->query();//遍历出对象中的全部属性
PHP5.6对命名空间的扩展

use可以导入函数可以常量空间

此处代码暂时有问题,暂不讨论。
详细相关请参考:PHP手册 使用命名空间:别名/导入

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值