现在我们来了解一下面向对象的一个封装性的问题

封装性:在我的理解里面 可以理解为一个u盘 我们使用u盘的接口与电脑进行数据之间的交互 但是我们不能看到里面的结构 这个特性我们可以称为封装性

好处:利用这个特性我们可以最大程度的提高代码的质量 我们在其他代码中只要对接口进行引用不用每次都写 提高代码的自量 以及减少排除bug的难度

现在我们来思考个问题:个人电脑都有一个密码,不想让其它人随意的登陆,在你电脑里面拷贝和粘贴。还有就是像人这个对象, 身高和年龄的属性, 只能是自己来增涨,不可以让别人随意的赋值等等。

我们使用private这个关键词对代码进行封装

private $name;	// 把人的姓名使用private关键字进行封装
private $sex;	// 把人的性别使用private关键字进行封装
private $age;	// 把人的年龄使用private关键字进行封装
private function run(){……} // 把人的走路方法使用private关键字进行封装

  注意:只要成员属性前面有其他的关键字,那么就要去掉var

<?php
class Person
{
	// 下面是人的成员属性
	private $name;		// 人的名子,被private封装上了
	private $sex;		// 人的性别, 被private封装上了
	private $age;		// 人的年龄, 被private封装上了

	// 这个人可以说话的方法
	function say()
	{
		echo "我的名子叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age;
	}

	// 这个人可以走路的方法, 被private封装上了
	private function run()
	{
		echo "这个人在走路";
	}
}

// 实例化一个人的实例对象
$p1 = new Person();

// 试图去给私有的属性赋值, 结果会发生错误
$p1->name = "张三";
$p1->sex = "男";
$p1->age = 20;

// 试图去打印私有的属性, 结果会发生错误
echo $p1->name;
echo $p1->sex;
echo $p1->age;

// 试图去打印私有的成员方法, 结果会发生错误
$p1->run();
?>

  

输出结果为:

Fatal error: Cannot access private property Person::$name
Fatal error: Cannot access private property Person::$sex
Fatal error: Cannot access private property Person::$age
Fatal error: Cannot access private property Person::$name
Fatal error: Call to private method Person::run() from context ' '

没有加任何访问控制,默认的是public的,任何地方都可以访问。

// 这个人可以说话的方法, 说出自己的私有属性,在这里也可以访问私有方法
function say()
{
	echo "我的名子叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age;

	// 在这里也可以访问私有方法
	//$this->run();
}

  因为成员方法say()是公有的, 所以我们在类的外部调用say()方法是可以的,改变上面的代码:

<?php
class Person
{
	// 下面是人的成员属性
	private $name;	//人的名子,被private封装上了
	private $sex;	//人的性别, 被private封装上了
	private $age;	//人的年龄, 被private封装上了

	// 定义一个构造方法参数为私有的属性姓名$name、性别$sex和年龄$age进行赋值
	function __construct($name, $sex, $age)
	{
		// 通过构造方法传进来的$name给私有成员属性$this->name赋初使值
		$this->name = $name;

		// 通过构造方法传进来的$sex给私有成员属性$this->sex赋初使值
		$this->sex = $sex;

		// 通过构造方法传进来的$age给私有成员属性$this->age赋初使值
		$this->age = $age;
	}

	// 这个人可以说话的方法, 说出自己的私有属性,在这里也可以访问私有方法
	function say()
	{
		echo "我的名子叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age;
	}
}

// 通过构造方法创建3个对象$p1、p2、$p3,分别传入三个不同的实参为姓名、性别和年龄
$p1 = new Person("张三", "男", 20);
$p2 = new Person("李四", "女", 30);
$p3 = new Person("王五", "男", 40);

// 下面访问$p1对象中的说话方法
$p1->say();

// 下面访问$p2对象中的说话方法
$p2->say();

// 下面访问$p3对象中的说话方法
$p3->say();
?>

  因为构造方法是默认的公有方法(构造方法不要设置成私有的),如果设置称为私有的话,就等同将u盘中的唯一一个接口封死,我们就不能对这个类进行访问

上面的例子中我们可以看到, 私有的成员只能在类的内部使用, 不能被类外部直接来存取 但是我们有时候有需要对私有属性进行赋值和读取,我们需要给类的外部提供一些可以存取的接口。

prvate $age; // 私有的属性年龄
function setAge($age) // 为外部提供一个公有设置年龄的方法
{
	if ($age<0 || $age>130) // 在给属性赋值的时候,为了避免非法值设置给属性
	return;
	$this->age = $age;
}

function getAge() // 为外部提供一个公有获取年龄的方法
{
	return($this->age);
}

  下面我们要了解一下__set,__get,__isset,__unset四个方法的应用

经过上面的讲解可能会有疑问 那么我们如何对私有类进行操作呢?????

__set设置:__get

<?php
//__get()方法用来获取私有属性
function __get($property_name)
{
	if (isset($this->$property_name))
	{
		return ($this->$property_name);
	}
	else
	{
		return (NULL);
	}
}

//__set()方法用来设置私有属性
function __set($property_name, $value)
{
	$this->$property_name = $value;
}

  一个完整的示例:

<?php
class Person
{
	// 下面是人的成员属性, 都是封装的私有成员
	private $name;		//人的名子
	private $sex;		//人的性别
	private $age;		//人的年龄

	//__get()方法用来获取私有属性
	function __get($property_name)
	{
		echo "在直接获取私有属性值的时候,自动调用了这个__get()方法<br />";
		if (isset($this->$property_name))
		{
			return ($this->$property_name);
		}
		else
		{
			return NULL;
		}
	}

	//__set()方法用来设置私有属性
	function __set($property_name, $value)
	{
		echo "在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值<br />";
		$this->$property_name = $value;
	}
}

$p1 = new Person();

// 直接为私有属性赋值的操作, 会自动调用__set()方法进行赋值
$p1->name = "张三";
$p1->sex = "男";
$p1->age = 20;

// 直接获取私有属性的值, 会自动调用__get()方法,返回成员属性的值
echo "姓名:" . $p1->name . "<br />";
echo "性别:" . $p1->sex . "<br />";
echo "年龄:" . $p1->age . "<br />";
?>

  

程序执行结果:

在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接获取私有属性值的时候,自动调用了这个__get()方法
姓名:张三
在直接获取私有属性值的时候,自动调用了这个__get()方法
性别:男
在直接获取私有属性值的时候,自动调用了这个__get()方法
年龄:20

以上代码如果不加上__get()和__set()方法,程序就会出错,因为不能在类的外部操作私有成员,而上面的代码是通过自动调用__get()和__set()方法来帮助我们直接存取封装的私有成员的。

如果在一个对象外面使用“isset()”这个函数去测定对象里面的成员是否被设定可不可以用它呢?分两种情况,如果对象里面成员是公有的,我们就可以使用这个函数来测定成员属性,如果是私有的成员属性,这个函数就不起作用了,原因就是因为私有的被封装了,在外部不可见。那么我们就不可以在对象的外部使用“isset()”函数来测定私有成员属性是否被设定了呢?可以,你只要在类里面加上一个“__isset()”方法就可以了,当在类外部使用”isset()”函数来测定对象里面的私有成员是否被设定时,就会自动调用类里面的“__isset()”方法了帮我们完成这样的操作,“__isset()”方法也可以做成私有的。你可以在类里面加上下面这样的代码就可以了:

private function __isset($nm)
{
	echo "当在类外部使用isset()函数测定私有成员$nm时,自动调用<br />";

	return isset($this->$nm);
}

完整例子

<?php
class Person
{
	// 下面是人的成员属性
	private $name;		//人的名子
	private $sex;		//人的性别
	private $age;		//人的年龄

	// __get()方法用来获取私有属性
	private function __get($property_name)
	{
		if (isset($this->$property_name))
		{
			return ($this->$property_name);
		}
		else
		{
			return NULL;
		}
	}

	// __set()方法用来设置私有属性
	private function __set($property_name, $value)
	{
		$this->$property_name = $value;
	}

	// __isset()方法
	private function __isset($nm)
	{
		echo "isset()函数测定私有成员时,自动调用<br />";
		return isset($this->$nm);
	}

	//__unset()方法
	private function __unset($nm)
	{
		echo "当在类外部使用unset()函数来删除私有成员时自动调用的<br />";
		unset($this->$nm);
	}
}

$p1 = new Person();
$p1->name = "this is a person name";

// 在使用isset()函数测定私有成员时,自动调用__isset()方法帮我们完成,返回结果为true
echo var_dump(isset($p1->name)) . "<br >";
echo $p1->name . "<br />";

// 在使用unset()函数删除私有成员时,自动调用__unset()方法帮我们完成,删除name私有属性
unset($p1->name);

// 已经被删除了,所这行不会有输出
echo $p1->name;
?>

  

输出结果为:

isset()函数测定私有成员时,自动调用
boolean true
this is a person name
当在类外部使用unset()函数来删除私有成员时自动调用的
isset()函数测定私有成员时,自动调用

  下面我们要来了解的是继承的知识

下面是人类的代码

// 定义一个“人”类做为父类
class Person
{
	// 下面是人的成员属性
	var $name;	//人的名子
	var $sex;	//人的性别
	var $age;	//人的年龄

	// 定义一个构造方法参数为属性姓名$name、性别$sex和年龄$age进行赋值
	function __construct($name, $sex, $age)
	{
		$this->name = $name;
		$this->sex = $sex;
		$this->age = $age;
	}

	// 这个人可以说话的方法, 说出自己的属性
	function say()
	{
		echo "我的名子叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age;
	}
}

  下面是学生类的代码

class Student
{
	// 下面是人的成员属性
	var $name;		// 人的名字
	var $sex;		// 人的性别
	var $age;		// 人的年龄
	var $school;	// 学生所在学校的属性

	// 定义一个构造方法参数为属性姓名$name、性别$sex 和年龄$age 进行赋值
	function __construct($name = "", $sex = "", $age = "", $school = "")
	{
		$this->name = $name;
		$this->sex = $sex;
		$this->age = $age;
		$this->school = $school;
	}

	// 这个人可以说话的方法, 说出自己的属性
	function say()
	{
		echo "我的名字叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age . "<br />";
	}

	// 这个学生学习的方法
	function study()
	{
		echo "我的名字叫:" . $this->name . " 我正在" . $this->school . "学习<br />";
	}
}

  对学生类进行简化

class Student extends Person
{
	var $school;	// 学生所在学校的属性

	// 这个学生学习的方法
	function study()
	{
		echo "我的名字叫:" . $this->name . " 我正在" . $this->school . "学习<br />";
	}
}

  现在我们要考虑的是重载的问题

这个时候你可能会有疑问 php 好像是不能重载的,因为PHP是一门若语言的,传统意义上的重载是有多个的方法名相同的方法,但是带有不同个数的参,我们利用参数的不同调用不同的接口

 我所说的重载是子类对父类的一个覆盖

<?
// 定义一个"人"类做为父类
class Person
{
	// 下面是人的成员属性
	var $name;		// 人的名子
	var $sex;		// 人的性别
	var $age;		// 人的年龄

	// 定义一个构造方法参数为属性姓名$name、性别$sex和年龄$age进行赋值
	function __construct($name, $sex, $age)
	{
		$this->name = $name;
		$this->sex = $sex;
		$this->age = $age;
	}

	// 这个人可以说话的方法, 说出自己的属性
	function say()
	{
		echo "我的名子叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age;
	}
}

class Student extends Person
{
	var $school; // 学生所在学校的属性

	// 这个学生学习的方法
	function study()
	{
		echo "我的名子叫:" . $this->name . " 我正在" . $this->school . " 学习";
	}

	// 这个学性可以说话的方法, 说出自己所有的属性,覆盖了父类的同名方法
	function say()
	{
		echo "我的名子叫:" . $this->name . " 性别:" . $this->sex . " 我的年龄是:" . $this->age . " 我在" . $this->school . "上学";
	}
}
?>

  这样就能实现了 这种方法归根到底是的要点是:

1。子类要对父类继承

2.子类的方法名要与父类的方法名相同

这个时候我们可能发现如果这个方法中有1000条代码那么 实现起来很不方便

此时我们,使用“parent::方法名”的方试来调用父类中被覆盖的方法;

class Student extends Person
{
	var $school;	// 学生所在学校的属性

	// 这个学生学习的方法
	function study()
	{
		echo "我的名子叫:" . $this->name . " 我正在" . $this->school . "学习";
	}

	// 这个学性可以说话的方法, 说出自己所有的属性,覆盖了父类的同名方法
	function say()
	{

		// 使用父类的"类名::"来调用父类中被覆盖的方法;
		// Person::say();

		// 或者使用"parent::"的方试来调用父类中被覆盖的方法;
		parent::say();

		// 加上一点自己的功能
		echo "我的年龄是:" . $this->age . " 我在" . $this->school . "上学";
	}
}

  对public,private,protected的区别

<?php
/**
 * Define MyClass
 */
class MyClass
{
	// Contructors must be public
	public function __construct() { }

	// Declare a public method
	public function MyPublic() { }

	// Declare a protected method
	protected function MyProtected() { }

	// Declare a private method
	private function MyPrivate() { }

	// This is public
	function Foo()
	{
		$this->MyPublic();
		$this->MyProtected();
		$this->MyPrivate();
	}
}

$myclass = new MyClass;
$myclass->MyPublic();		// Works
$myclass->MyProtected();	// Fatal Error
$myclass->MyPrivate();		// Fatal Error
$myclass->Foo();			// Public, Protected and Private work

/**
 * Define MyClass2
 */
class MyClass2 extends MyClass
{
	// This is public
	function Foo2()
	{
		$this->MyPublic();
		$this->MyProtected();
		$this->MyPrivate();		// Fatal Error
	}
}

$myclass2 = new MyClass2;
$myclass2->MyPublic();	// Works
$myclass2->Foo2();		// Public and Protected work, not Private
?>

  从上面的代码我们可以总结如下

public:可以直接进行外部访问

protected 间接的外部访问 像U盘和电脑一样 访问需要一个接口 而那个接口就是需要一个子类 (子类继承了父类的protected)

private 不能通过外部访问

既然谈到继承的问题 如果我们想要一个类不被继承那么我们可以用final 去进行定义(只能定义类和方法,不能定义成员属性)

1.final 标记的类不能被继承

2.final标记的方法不能被子类覆盖

<?php
final class Person
{
	function say()
	{

	}
}

class Student extends Person
{
	function say()
	{

	}
}
?>

  

会出现下面错误:

Fatal error: Class Student may not inherit from final class (Person)
<?php
class Person
{
	final function say()
	{

	}

}

class Student extends Person
{
	function say()
	{

	}
}
?>

  理解static 和const的关键关键字的使用(self:)

static 字面上的意思就是静态的意思 现在你可能会问静态使用静态有什么好处?使用静态的好处是:如果示例话成千上万“人”的对象,里面都有一个共有的属性比如国籍“中国”,那么我们可以建国籍这个属性设置为静态,在内存在开辟出一个位置,实例化的过程中成千上万的人都会访问内存中这个位置

static成员能够限制外部的访问,因为static的成员是属于类的,是不属于任何对象实例,是在类第一次被加载的时候分配的空间,其他类是无法访问的,只对类的实例共享,能一定程度对类该成员形成保护;

这一点有点像网站中的全局变量

<?
class Person
{
	// 下面是人的静态成员属性
	public static $myCountry = "中国";

	// var $name; //人的名子

	// 这是人的静态成员方法
	public static function say()
	{
		echo "我是中国人";
	}
}

// 输出静态属性
echo Person::$myCountry;

// 访问静态方法
Person::say();

// 重新给静态属性赋值
Person::$myCountry = "美国";
echo Person::$myCountry;
?>

  结果是:

中国我是中国人美国

也可以这么写

<?php
class MyClass
{
	// 定义一个常量constant
	const constant = 'constant value';

	function showConstant()
	{
		echo self::constant . " "; // 使用self访问,不要加“$”
	}
}

echo MyClass::constant . " "; // 使用类名来访问,也不加“$”

$class = new MyClass();
$class->showConstant();
// echo $class::constant; // 是不允许的
?>

  用“const”修饰的成员属性的访问方式和“static”修饰的成员访问的方式差不多,也是使用“类名”,在方法里面使用“self”关键字。但是不用使用“$”符号,也不能使用对象来访问。

<?php
class MyClass
{
	// 定义一个常量constant
	const constant = 'constant value';

	function showConstant()
	{
		echo self::constant . " "; // 使用self访问,不要加“$”
	}
}

echo MyClass::constant . " "; // 使用类名来访问,也不加“$”

$class = new MyClass();
$class->showConstant();
// echo $class::constant; // 是不允许的
?>

  为了便于直接的对类进行操作 我们引入了__toString()

<?php
// Declare a simple class
class TestClass
{
	public $foo;

	public function __construct($foo)
	{
		$this->foo = $foo;
	}

	// 定义一个__toString方法,返加一个成员属性$foo
	public function __toString()
	{
		return $this->foo;
	}
}

$class = new TestClass('Hello');

// 直接输出对象
echo $class;
?>

  注意的是__toString一定要有个返回值

php面向对象编程(二)的更多相关文章

  1. Python进阶之面向对象编程(二)

    Python面向对象编程(二) .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans GB& ...

  2. python之路---面向对象编程(二)

    类的继承 1.在python3中,只有新式类,新式类的继承方式为:广度优先.而python2中,经典类的继承方式为:深度优先.那么我们来看看深度优先和广度优先的区别吧 如下图,为类之间的继承关系.B, ...

  3. Java面向对象编程(二)

    上一篇博文里总结了面向对象三大特性在Java中的体现.如今谈一谈Java中的抽象类,接口,内部类等特性. 一. 抽象类 public abstract class Shape { public int ...

  4. Python之路【第五篇续】:面向对象编程二

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABgQAAALaCAIAAABxja8cAAAgAElEQVR4nOzd6X9Tdd74/+uv+f5uzF

  5. Python入门之面向对象编程(二)python类的详解

    本文通过创建几个类来覆盖python中类的基础知识,主要有如下几个类 Animal :各种属性.方法以及属性的修改 Dog :将方法转化为属性并操作的方法 Cat :私人属性讲解,方法的继承与覆盖 T ...

  6. python之面向对象编程二

    类的成员 类的成员可以分为三大类:字段.方法.属性. 字段:普通字段.静态字段. 方法:普通方法.类方法.静态方法 属性:普通属性. 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多 ...

  7. Delphi_09_Delphi_Object_Pascal_面向对象编程

    今天这里讨论一下Delphi中的面向对象编程,这里不做过多过细的讨论,主要做提纲挈领的描述,帮助自己抓做重点. 本随笔分为两部分: 一.面向对象编程 二.面向对象编程详细描述 ------------ ...

  8. python基础-面向对象编程

    一.三大编程范式 编程范式即编程的方法论,标识一种编程风格 三大编程范式: 1.面向过程编程 2.函数式编程 3.面向对象编程 二.编程进化论 1.编程最开始就是无组织无结构,从简单控制流中按步写指令 ...

  9. 面向对象编程(十二)——final关键字

    final关键字 Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类.非抽象类成员方法和变量. 在Java中,final关键字可以用来修饰类.方法和变量(包括成员变量和 ...

随机推荐

  1. Android 6.0 权限管理最佳实践

    博客: Android 6.0 运行时权限管理最佳实践 github: https://github.com/yanzhenjie/AndPermission

  2. Objective-C Mojo和Django 对接

    最近在做资料类app需要一个好的资源管理工具,excel在这方面非常好,不过能第一非常low,第二数据量一大查询就是个问题. 因此,我使用django做了个资源管理小工具.好处还是很明显的 (1)可以 ...

  3. MVC学习系列3--怎么从控制器向视图传递数据

    在MVC中,从控制器到视图,传递数据,可以使用 ViewData 和 ViewBag:同样从视图到控制器,传递数据,可以使用Post,QueryString,或者隐藏域:最后从控制器到控制器,传递数据 ...

  4. sqlserver2012更改文件组

    1.查看文件组 sql语句 SELECT Data_located_on_filegroup = fg.groupname, Table_name = obj.name FROM sysfilegro ...

  5. [windows]win10家庭版切换到管理员账户

    背景:很多时候,在安装或者运行某些程序时会需要到管理员账户运行.而在win10家庭版却没有明显的位置可以让用户简单的进行切换.因此,有了以下的方法. 方法: 1.在搜索框中输入CMD,右键以管理员方式 ...

  6. centos7安装vncserver

    :# yum install tigervnc-server -y :cp /lib/systemd/system/vncserver@.service /etc/systemd/system/vnc ...

  7. 《Java JDK7 学习笔记》课后练习题1

    1.()组织负责监督审查Java相关技术规格的演进. A. JCP B. Apache C. EU D. W3C 2.Java技术规格必须以()正式文件提交审查. A. RFC B. JSR C. I ...

  8. 关于oracle中数据类型的选择

    由于是初学,犯了如下错误: 生成表的主键id时,用当前时间的毫秒值.而在oracle中定义主键id时,用的数据类型是char(32).在mybatis中通过id取数据怎么也取不出来.想了好几天,本来以 ...

  9. CentOS下配置nginx conf/koi-win为同一文件的各类错误

    今天配置CentOS6.5下安装Nginx + php7 + mysql5.7.15遇到了一些坑.本来家里的电脑在配置环境的时候没有问题,拿去公司的电脑上就是到处报错.不知道是不是人品问题.今晚在家重 ...

  10. PHP+Apache+Zend Studio+MySql+Navicat+phpAdmin

    本文章介绍整个PHP开发环境的搭建 数据库:MySql  5.5.50 数据库软件:Navicat 11.1.20和phpAdmin 4.6.5.1任选 php库:PHP 7.0.13 服务器:Apa ...