PHP命名空间
可以更好地组织代码,与Java中的包类似。
Test1.php
<?php
namespace Test1;//命名空间Test1 function test(){ echo __FILE__; } Test2.php <?php namespace Test2; //命名空间Test2 function test(){ echo __FILE__;//打印当前文件所在的绝对路径。 } Test.php <?php require 'Test1.php'; require 'Test2.php'; Test1\test();//通过这种方式,使用命名空间下的方法或者类。Test1表示命名空间,test()表示该命名空间下的一个方法。 echo "<br>"; Test2\test();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
运行结果
总结:通过以上代码,可以看到,在不同的命名空间下,可以有相同的类名或者方法名。
类自动载入
随着PHP项目的变大,会导致一个PHP文件的前面有很多的require去包含各种依赖的PHP文件。如果某个类删除,但是在别的文件里有导入的情况,就会导致致命错误。解决以上问题的方法,就是__autoload()函数。
Test1.php
<?php
class Test1{
static function test(){ echo __FILE__; } } Test2.php <?php class Test2 { static function test(){ echo __FILE__; } } Test.php <?php Test1::test(); Test2::test(); function __autoload($class){ $dir = __DIR__; $requireFile = $dir."\\".$class.".php"; require $requireFile; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
PHP就是用这段代码,去动态的载入需要包含的文件。当使用某个类,而这个类没有包含到文件中时,就会调用__autoload()函数,去动态的加载这个文件。但是,当使用多个框架时,每个框架都会有自己的__autoload()实现,所以,会导致文件重复导入。
<?php
spl_autoload_register('autoload1');
spl_autoload_register('autoload2');
//将实现自动导入的函数,以字符串的形式传入该函数中,即可解决重复导入文件导致的错误问题。
Test1::test();
Test2::test();
function autoload1($class){ $dir = __DIR__; $requireFile = $dir."\\".$class.".php"; require $requireFile; } function autoload2($class){ $dir = __DIR__; $requireFile = $dir."\\".$class.".php"; require $requireFile; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
PSR-0
- PHP的命名空间必须与绝对路径一致。
- 类名首字母大写。
- 除了入口文件之外,其他的PHP文件必须是一个类,不能有执行的代码。
设计模式
单例模式解决的是如何在整个项目中创建唯一对象实例的问题,工厂模式解决的是如何不通过new建立实例对象的方法。
单例模式
- $_instance必须声明为静态的私有变量
- 构造函数和析构函数必须声明为私有,防止外部程序new 类从而失去单例模式的意义
- getInstance()方法必须设置为公有的,必须调用此方法 以返回实例的一个引用
- ::操作符只能访问静态变量和静态函数
- new对象都会消耗内存
- 使用场景:最常用的地方是数据库连接。
- 使用单例模式生成一个对象后, 该对象可以被其它众多对象所使用。
- 私有的__clone()方法防止克隆对象
单例模式,使某个类的对象仅允许创建一个。构造函数private修饰,
申明一个static getInstance方法,在该方法里创建该对象的实例。如果该实例已经存在,则不创建。比如只需要创建一个数据库连接。
工厂模式
工厂模式,工厂方法或者类生成对象,而不是在代码中直接new。
使用工厂模式,可以避免当改变某个类的名字或者方法之后,在调用这个类的所有的代码中都修改它的名字或者参数。
Test1.php
<?php
class Test1{
static function test(){ echo __FILE__; } } Factory.php <?php class Factory{ /* * 如果某个类在很多的文件中都new ClassName(),那么万一这个类的名字 * 发生变更或者参数发生变化,如果不使用工厂模式,就需要修改每一个PHP * 代码,使用了工厂模式之后,只需要修改工厂类或者方法就可以了。 */ static function createDatabase(){ $test = new Test1(); return $test; } } Test.php <?php spl_autoload_register('autoload1'); $test = Factory::createDatabase(); $test->test(); function autoload1($class){ $dir = __DIR__; $requireFile = $dir."\\".$class.".php"; require $requireFile; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
Test1.php
<?php
class Test1{
protected static $tt; private function __construct(){} static function getInstance(){ if(self::$tt){ echo "对象已经创建<br>"; return self::$tt; }else { self::$tt = new Test1(); echo "创建对象<br>"; return self::$tt; } } function echoHello(){ echo "Hello<br>"; } } Test.php <?php spl_autoload_register('autoload1'); $test = Test1::getInstance(); $test->echoHello(); $test = Test1::getInstance(); $test->echoHello(); $test = Test1::getInstance(); $test->echoHello(); $test = Test1::getInstance(); $test->echoHello(); function autoload1($class){ $dir = __DIR__; $requireFile = $dir."\\".$class.".php"; require $requireFile; }
策略模式
策略模式,将一组特定的行为和算法封装成类,以适应某些特定的上下文环境。
eg:假如有一个电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且所有的广告位展示不同的广告。在传统的代码中,都是在系统中加入各种if else的判断,硬编码的方式。如果有一天增加了一种用户,就需要改写代码。使用策略模式,如果新增加一种用户类型,只需要增加一种策略就可以。其他所有的地方只需要使用不同的策略就可以。
首先声明策略的接口文件,约定了策略的包含的行为。然后,定义各个具体的策略实现类。
UserStrategy.php
<?php
/*
* 声明策略文件的接口,约定策略包含的行为。
*/
interface UserStrategy { function showAd(); function showCategory(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
FemaleUser.php
<?php
require_once 'Loader.php';
class FemaleUser implements UserStrategy { function showAd(){ echo "2016冬季女装"; } function showCategory(){ echo "女装"; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
MaleUser.php
<?php
require_once 'Loader.php';
class MaleUser implements UserStrategy { function showAd(){ echo "IPhone6s"; } function showCategory(){ echo "电子产品"; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
Page.php//执行文件
<?php
require_once 'Loader.php';
class Page { protected $strategy; function index(){ echo "AD"; $this->strategy->showAd(); echo "<br>"; echo "Category"; $this->strategy->showCategory(); echo "<br>"; } function setStrategy(UserStrategy $strategy){ $this->strategy=$strategy; } } $page = new Page(); if(isset($_GET['male'])){ $strategy = new MaleUser(); }else { $strategy = new FemaleUser(); } $page->setStrategy($strategy); $page->index();
执行结果图:
总结:
通过以上方式,可以发现,在不同用户登录时显示不同的内容,但是解决了在显示时的硬编码的问题。如果要增加一种策略,只需要增加一种策略实现类,然后在入口文件中执行判断,传入这个类即可。实现了解耦。
实现依赖倒置和控制反转 (有待理解)
通过接口的方式,使得类和类之间不直接依赖。在使用该类的时候,才动态的传入该接口的一个实现类。如果要替换某个类,只需要提供一个实现了该接口的实现类,通过修改一行代码即可完成替换