首页 > 编程技术 > php

php设计模式——单例模式(Singleton)的常见应用场景

发布时间:2016-11-25 16:19

单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此有些设计大师并把把其称为设计模式之一。

单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此有些设计大师并把把其称为设计模式之一。

这里又不具体讲如何实现单例模式和介绍其原理(因为这方便的已经有太多的好文章介绍了),如果对单例模式不了解的可以先看下:http://terrylee.cnblogs.com/archive/2005/12/09/293509.html 。当然也可以自己搜索。

好多没怎么使用过的人可能会想,单例模式感觉不怎么用到,实际的应用场景有哪些呢?以下,我将列出一些就在咱们周边和很有意义的单例应用场景。

1. Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~

2. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

3. 网站的计数器,一般也是采用单例模式实现,否则难以同步。

4. 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。

5. Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。

6. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。

7. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。

8. 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。

9. HttpApplication 也是单位例的典型应用。熟悉ASP.Net(IIS)的整个请求生命周期的人应该知道HttpApplication也是单例模式,所有的HttpModule都共享一个HttpApplication实例.

 

总结以上,不难看出:

单例模式应用的场景一般发现在以下条件下:

(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。

(2)控制资源的情况下,方便资源之间的互相通信。如线程池等。

抽象类就是一个类的服务提供商,拥有众多服务,你不用必须用,当需要的时候你来用就可以,如果你觉得不提供服务不满意,你还可以自己来做。而 abstract function 方法和interface有些相似,就是父类中生声明的方法,子类中必须实现,但是没有用abstract声明的方法将成为子类的公共方法,没有必要在子 类中必须实现


1.php 接口类:interface

其实他们的作用很简单,当有很多人一起开发一个项目时,可能都会去调用别人写的一些类,那你就会问,我怎么知道他的某个功能的实现方法是怎么命名的呢,这个时候php接口类就起到作用了,当我们定义了一个接口类时,它里面的方式是下面的子类必须实现的,比如 :

 代码如下 复制代码
interface Shop
{
    public function buy($gid);
    public function sell($gid);
    public function view($gid);
}



我声明一个shop接口类,定义了三个方法:买(buy),卖(sell),看(view),那么继承此类的所有子类都必须实现这3个方法少一个都 不行,如果子类没有实现这些话,就无法运行。实际上接口类说白了,就是一个类的模板,一个类的规定,如果你属于这类,你就必须遵循我的规定,少一个都不 行,但是具体你怎么去做,我不管,那是你的事,如:

 代码如下 复制代码
class BaseShop implements Shop
{
    public function buy($gid)
    {
        echo('你购买了ID为 :'.$gid.'的商品');
    }

    public function sell($gid)
    {
        echo('你卖了ID为 :'.$gid.'的商品');
    }

    public function view($gid)
    {
        echo('你查看了ID为 :'.$gid.'的商品');
    }
}



你想想,在一个多人合作的大项目里面,有了接口类是多么的方便,这样你就不用去问别人,你的某某功能的方法名是什么了,当然如果你们喜欢这样我也没有办法。

结论 : 接口类就是一个类的领导者,指明方向,子类必须完成它指定方法。

2.php 抽象类 : abstract


其实抽象类和接口类有一部分很像,记得在哪里看见这样一句话,抽象类就把类像的部分抽出来,这句看上去很搞笑,其实它说出了抽象类的真理,抽象类的 作用是,当你发现你的很多类里面用很多方法你不断的在重复写,那你就可以考虑使用抽象类了,你可能会说“我不是可以重写一个类每个公共类我个实例化一个这 个公共类,调用相同的方法就可以了”,这里是可以,实际上抽象类做的工作也就是这个,不过他省去了你实例化的这个步骤,让你就像直接调用本类方法一样方 便,而且你还可以重载这个方法。如:

 代码如下 复制代码
abstract class BaseShop
{
    public function buy($gid)
    {
        echo('你购买了ID为 :'.$gid.'的商品');
    }

    public function sell($gid)
    {
        echo('你卖了ID为 :'.$gid.'的商品');
    }

    public function view($gid)
    {
        echo('你查看了ID为 :'.$gid.'的商品');
    }
}

class BallShop extends BaseShop
{
    var $itme_id = null;
    public function __construct()
    {
        $this->itme_id = 2314;
    }

    public function open()
    {
        $this->sell($this->itme_id);
    }
}




这里是一个例子,想上面一样我定义了一个商店类,抽出了它所有像的部分,买(buy),卖(sell),看(view),并且抽象类里都实现了这些方法,那么继承它的子类就自动获得了这些方法,子类就做它自己独特的东西,介绍代码的重复,提高复用性。

结 论: 抽象类就是一个类的服务提供商,拥有众多服务,你不用必须用,当需要的时候你来用就可以,如果你觉得不提供服务不满意,你还可以自己来做。而 abstract function 方法和interface有些相似,就是父类中生声明的方法,子类中必须实现,但是没有用abstract声明的方法将成为子类的公共方法,没有必要在子 类中必须实现

一个sphinx将python的注释生成文档例子过程的安装与生成过程,希望此例子能给各位带来帮助。


安装

sudo pip install sphinx

初始化
进入你代码所在的目录,输入以下内容

sphinx-quickstart

会出来一系列要选填的东西,按照我的填入就可以了

Welcome to the Sphinx 1.2.3 quickstart utility.

Please enter values for the following settings (just press Enter to
accept a default value, if one is given in brackets).

Enter the root path for documentation.
> Root path for the documentation [.]: doc

You have two options for placing the build directory for Sphinx output.
Either, you use a directory "_build" within the root path, or you separate
"source" and "build" directories within the root path.
> Separate source and build directories (y/n) [n]: n

Inside the root directory, two more directories will be created; "_templates"
for custom HTML templates and "_static" for custom stylesheets and other static
files. You can enter another prefix (such as ".") to replace the underscore.
> Name prefix for templates and static dir [_]:

The project name will occur in several places in the built documentation.
> Project name: bz_python_lib
> Author name(s): bigzhu

Sphinx has the notion of a "version" and a "release" for the
software. Each version can have multiple releases. For example, for
Python the version is something like 2.5 or 3.0, while the release is
something like 2.5.1 or 3.0a1.  If you don't need this dual structure,
just set both to the same value.
> Project version: 1.0
> Project release [1.0]:

The file name suffix for source files. Commonly, this is either ".txt"
or ".rst".  Only files with this suffix are considered documents.
> Source file suffix [.rst]:

One document is special in that it is considered the top node of the
"contents tree", that is, it is the root of the hierarchical structure
of the documents. Normally, this is "index", but if your "index"
document is a custom template, you can also set this to another filename.
> Name of your master document (without suffix) [index]:

Sphinx can also add configuration for epub output:
> Do you want to use the epub builder (y/n) [n]:

Please indicate if you want to use one of the following Sphinx extensions:
> autodoc: automatically insert docstrings from modules (y/n) [n]: y
> doctest: automatically test code snippets in doctest blocks (y/n) [n]:
> intersphinx: link between Sphinx documentation of different projects (y/n) [n]:
> todo: write "todo" entries that can be shown or hidden on build (y/n) [n]:
> coverage: checks for documentation coverage (y/n) [n]:
> pngmath: include math, rendered as PNG images (y/n) [n]:
> mathjax: include math, rendered in the browser by MathJax (y/n) [n]:
> ifconfig: conditional inclusion of content based on config values (y/n) [n]:
> viewcode: include links to the source code of documented Python objects (y/n) [n]: y

A Makefile and a Windows command file can be generated for you so that you
only have to run e.g. `make html' instead of invoking sphinx-build
directly.
> Create Makefile? (y/n) [y]: y
> Create Windows command file? (y/n) [y]: n
路径我希望是在当面目录的 doc 目录里,所以我加入了 doc,把生成 doc 相关的东西放到 doc 目录里面会妥当一些.
项目名称和作者你就别照着我的填了.
autodoc 要改成y
其他的看你的需要来改就可以了.

输错了没关系.到doc/conf.py自己改就可以了.

从 docstring 生成 doc
配置修改
sphinx还是有些脑残的,自信的认为,源代码和它的那些乱七八糟的东西是放在一起的.

编辑 conf.py, 打开这行的注释,并且把.修改为..

sys.path.insert(0, os.path.abspath('..'))
生成 rst
到代码目录,执行以下命令

sphinx-apidoc -o ./doc ./
会生成对应 python 文件名的 rst 文件

Creating file ./doc/public.rst.
Creating file ./doc/test.rst.
Creating file ./doc/modules.rst.
生成 html
进入 doc 执行

cd doc
make html
打开 html, 愉快的浏览吧

cd _build/html/
open index.html
愉快的浏览 api 吧

memcached是一个超高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载了,现在我们就来看看如何配置memcached吧,希望能帮助到大家。

memcached的基本命令(安装、卸载、启动、配置相关)

-p 监听的端口
-l 连接的IP地址, 默认是本机
-d start 启动memcached服务
-d restart 重起memcached服务
-d stop|shutdown 关闭正在运行的memcached服务
-d install 安装memcached服务
-d uninstall 卸载memcached服务
-u 以的身份运行 (仅在以root运行的时候有效)
-m 最大内存使用,单位MB。默认64MB

-M 内存耗尽时返回错误,而不是删除项
-c 最大同时连接数,默认是1024
-f 块大小增长因子,默认是1.25
-n 最小分配空间,key+value+flags默认是48
-h 显示帮助

memcached的基本命令(memcached 启动后 用于对memcached管理的数据和本身运行状态相关的命令)

Command Description Example
get Reads a value get mykey
set Set a key unconditionally set mykey 0 60 5
add Add a new key add newkey 0 60 5
replace Overwrite existing key replace key 0 60 5
append Append data to existing key append key 0 60 15
prepend Prepend data to existing key prepend key 0 60 15
incr Increments numerical key value by given number incr mykey 2
decr Decrements numerical key value by given number decr mykey 5
delete Deletes an existing key delete mykey
flush_all Invalidate specific items immediately flush_all
Invalidate all items in n seconds flush_all 900
stats Prints general statistics stats
Prints memory statistics stats slabs
Prints memory statistics stats malloc
Print higher level allocation statistics stats items
stats detail
stats sizes
Resets statistics stats reset
version Prints server version. version
verbosity Increases log level verbosity
quit Terminate telnet session quit
对查看的信息的关键字中英文对照表

pid
memcache服务器的进程ID
uptime
服务器已经运行的秒数
time
服务器当前的unix时间戳
version
memcache版本
pointer_size
当前操作系统的指针大小(32位系统一般是32bit)
rusage_user
进程的累计用户时间
rusage_system
进程的累计系统时间
curr_items
服务器当前存储的items数量
total_items
从服务器启动以后存储的items总数量
bytes
当前服务器存储items占用的字节数
curr_connections
当前打开着的连接数
total_connections
从服务器启动以后曾经打开过的连接数
connection_structures
服务器分配的连接构造数
cmd_get
get命令(获取)总请求次数
cmd_set
set命令(保存)总请求次数
get_hits
总命中次数
get_misses
总未命中次数
evictions
为获取空闲内存而删除的items数(分配给memcache的空间用满后需要删除旧的items来得到空间分配给新的items)
bytes_read
总读取字节数(请求字节数)
bytes_written
总发送字节数(结果字节数)
limit_maxbytes
分配给memcache的内存大小(字节)
threads
当前线程数

下面是一段简单的测试代码,代码中对标识符为 'mykey' 的对象数据进行存取操作:

 

 代码如下 复制代码
<?php
// 包含 memcached 类文件
require_once('memcached-client.php');
// 选项设置
$options = array(
'servers' => array('192.168.1.1:11211'), //memcached 服务的地址、端口,可用多个数组元素表示多个 memcached 服务
'debug' => true, //是否打开 debug
'compress_threshold' => 10240, //超过多少字节的数据时进行压缩
'persistant' => false //是否使用持久连接
);
// 创建 memcached 对象实例
$mc = new memcached($options);
// 设置此脚本使用的唯一标识符
$key = 'mykey';
// 往 memcached 中写入对象
$mc->add($key, 'some random strings');
$val = $mc->get($key);
echo "n".str_pad('$mc->add() ', 60, '_')."n";
var_dump($val);
// 替换已写入的对象数据值
$mc->replace($key, array('some'=>'haha', 'array'=>'xxx'));
$val = $mc->get($key);
echo "n".str_pad('$mc->replace() ', 60, '_')."n";
var_dump($val);
// 删除 memcached 中的对象
$mc->delete($key);
$val = $mc->get($key);
echo "n".str_pad('$mc->delete() ', 60, '_')."n";
var_dump($val);
?>

是不是很简单,在实际应用中,通常会把数据库查询的结果集保存到 memcached 中,下次访问时直接从 memcached 中获取,而不再做数据库查询操作,这样可以在很大程度上减轻数据库的负担。通常会将 SQL 语句 md5() 之后的值作为唯一标识符 key。下边是一个利用 memcached 来缓存数据库查询结果集的示例(此代码片段紧接上边的示例代码):

 代码如下 复制代码


<?php
$sql = 'SELECT * FROM users';
$key = md5($sql); //memcached 对象标识符
if ( !($datas = $mc->get($key)) ) {
// 在 memcached 中未获取到缓存数据,则使用数据库查询获取记录集。
echo "n".str_pad('Read datas from MySQL.', 60, '_')."n";
$conn = mysql_connect('localhost', 'test', 'test');
mysql_select_db('test');
$result = mysql_query($sql);
while ($row = mysql_fetch_object($result))
$datas[] = $row;
// 将数据库中获取到的结果集数据保存到 memcached 中,以供下次访问时使用。
$mc->add($key, $datas);
} else {
echo "n".str_pad('Read datas from memcached.', 60, '_')."n";
}
var_dump($datas);
?>

可以看出,使用 memcached 之后,可以减少数据库连接、查询操作,数据库负载下来了,脚本的运行速度也提高了。

好啦,至此memcached基本架设完成了,如果有啥问题或者有啥偶说的不对的欢迎来联系偶

下文是介绍一个php版本交通银行网银支付接口开发例子,希望这个例子能帮助到各位。

概述:网银支付接口 和支付宝接口大体上差不多,主要的区别是 交通银行提供的 接口核心的比如,加密等是通过java实现的。所以,要想办法使php和java能正常的通信,为此。官方也提供了两套实现方法,一个是通过 socket 进行通信,另一个方法是通过 java 桥接。下面演示的是 socket方法:

1. 配置运行环境
1.1  安装java,自行到oracle官网下载 java,然后安装,并配置正确的 环境变量。
1.2  把 测试的证书导入到java 虚拟机;
 keytool " -import -keystore "java虚拟机放置证书的地址" -storepass changeit -alias test_bocommca -file "证书路径" 完成导入。
 例子:keytool" -import -keystore "C:\Program Files\Java\jre1.5\lib\security\cacerts" -storepass changeit -alias test_bocommca -file "C:\socket\cert\test_root.cer"

 1.3  修改配置文件(in/B2CMerchantSocket.xml):
  采用官方提供的测试 商号进行测试时,无需配置,否则要配置。具体看xml文件说明。

1.4  启动 socket 服务
        window:启动  start.bat 及可;
        linux: 启动  ohup  sh.start,sh&     //使当前脚本脱离终端,并在后台运行。

2. 将网银集成到现有的系统:(以mvc的结构进行说明):

2.1  将不变的参数 配置 写入配置文件:

 代码如下 复制代码

 $config['interfaceVersion']  = "1.0.0.0";   #接口版本
  $config['tranType']    =0; #交易类别  0:B:C
  $config['curType']        = 'CNY';           # 交易币种
  $config['notifyType']   =1;         #0=不通知 1=通知 2=抓取
  $config['merURL']   = "http://www.111cn.net /pay/notify";   # 主动通知url
  $config['goodsURL'        = 'http://www.111cn.net /goods/1.html';           #取货url
  $config['jumpSeconds']   =3;        #跳转时间
  $config['payBatchNo']   = '';     #商户批次号
  $config['proxyMerName']   = '';                 #代理商家名字
  $config['proxyMerType']   = '';                 #代理商类型
  $config['proxyMerCredentials']= '';                #代理商家批次号
  $config['netType']     = 0;                 #渠道编号

  //以下是 新接口需要的参数
  $config['socketUrl']         ="tcp://127.0.0.1:8891";  #socket url
  $config['merID']     ='301310063009501';    #商户id 3013100630095012
2.2 Model


/**
 * 交通银行支付类
 */
class Bocom extends CI_Model {
 private $arrReturn=array();
 private $socket;
 public function __construct() {
  parent::__construct ();
  //加载交通银行配置文件
  $this->config->load('bocom');
  $this->socket=$this->config->item('socketUrl');
 }
 /**
  * 支付方法
  *
  * @param unknown $arr_data=array(
  *  'bill_no'=>
  * )
  */
 public  function pay($arr_data){
  //获得表单传过来的数据
  $this->arrReturn['interfaceVersion'] = $this->config->item('interfaceVersion');
  $this->arrReturn['merID']       = $this->config->item('merID'); //商户号为固定
  $this->arrReturn['orderid']  = $arr_data['bill_no'];
  $this->arrReturn['orderDate']  = $arr_data['bill_date'];
  $this->arrReturn['orderTime']  = $arr_data['bill_time'];
  $this->arrReturn['tranType']  = $this->config->item('tranType');
  $this->arrReturn['amount']    = $arr_data['bill_fee'];
  $this->arrReturn['curType']  = $this->config->item('curType');
  $this->arrReturn['orderContent']  = isset($arr_data['bill_title'])?iconv('utf-8','gb2312',$arr_data["bill_title"]): '';   #订单内容
  $this->arrReturn['orderMono']     = isset($arr_data['bill_mono'])? iconv('utf-8','gb2312',$arr_data['bill_mono']):'';     #商家备注
  $this->arrReturn['phdFlag']       = isset($arr_data['phpFlag'])?$arr_data['phpFlag']:'';
  $this->arrReturn['notifyType']    = $this->config->item('notifyType');
  $this->arrReturn['merURL']        = $this->config->item('merURL');
  $this->arrReturn['goodsURL']      = $this->config->item('goodsURL');
  $this->arrReturn['jumpSeconds']   = $this->config->item('jumpSeconds');
  $this->arrReturn['payBatchNo']    = $this->config->item('payBatchNo');
  $this->arrReturn['proxyMerName']  = $this->config->item('proxyMerName');
  $this->arrReturn['proxyMerType']  = $this->config->item('proxyMerType');
  $this->arrReturn['proxyMerCredentials']= $this->config->item('proxyMerCredentials');
  $this->arrReturn['netType']        = $this->config->item('netType');
  //以下参数 不参与签名
  $this->arrReturn['issBankNo']      =isset($arr_data['code_id'])? trim($arr_data['code_id']):'';
  $tranCode = "cb2200_sign";
  $source='';
  $len = count($this->arrReturn)-1;$j=1;
  foreach($this->arrReturn as $v){
   if($j<=$len){
    $source.=$v."|";
   }
   $j++;
  }
  $source= substr($source, 0,strlen($source)-1);
     $fp= stream_socket_client($this->socket,$errno, $errstr, 30);   
     $retMsg="";
     if (!$fp) {
      log_message("info","socket连接失败");
      return false;
     } else
     {
     $in  = "<?xml version='1.0' encoding='gbk2312'?>";
  $in .= "<Message>";
  $in .= "<TranCode>".$tranCode."</TranCode>";
  $in .= "<MsgContent>".$source."</MsgContent>";
  $in .= "</Message>";
  fwrite($fp, $in);
       while (!feof($fp)) {
        $retMsg =$retMsg.fgets($fp, 1024);
       }
       fclose($fp);
     }
    if(false!==$xml_arr=$this->xmlParse($retMsg)){
       if(is_array($xml_arr)){
        foreach($xml_arr as $k=>$v){
         $this->arrReturn[$k]=$v;
        }
       }else{
        return false;
       }
    }else{
      return false;
    }
    return $this->arrReturn;
 }
 
 /**
  * 解析XML
  */
 public function xmlParse($retMsg){
  $arr=array();
  //解析返回xml
  $dom = new DOMDocument;
  $dom->loadXML($retMsg);
  $retCode = $dom->getElementsByTagName('retCode');
  $retCode_value = $retCode->item(0)->nodeValue;
  $errMsg = $dom->getElementsByTagName('errMsg');
  $errMsg_value = $errMsg->item(0)->nodeValue;
  $signMsg = $dom->getElementsByTagName('signMsg');
  $signMsg_value = $signMsg->item(0)->nodeValue;
  $orderUrl = $dom->getElementsByTagName('orderUrl');
  $orderUrl_value = $orderUrl->item(0)->nodeValue;
  $MerchID = $dom->getElementsByTagName('MerchID');
  $merID = $MerchID->item(0)->nodeValue;
  if($retCode_value != "0"){
   log_message("info","交易返回码:".$retCode_value);
   log_message("info","交易错误信息:".$errMsg_value);
            return false;
        }
   $arr['merSignMsg'] = $signMsg_value;
   $arr['merID']      = $merID;
    $arr['orderUrl']   = $orderUrl_value;     
   return $arr;
 }
 /**
  * 交通银行 支付通知
  * @return boolean|unknown
  */
 public function notify(){
  $tranCode = "cb2200_verify";
  if(!isset($_REQUEST['notifyMsg'])){
   log_message("error","网银支付通知·非法请求");
   return false;
  }
     $notifyMsg = $_REQUEST["notifyMsg"];
  log_message("error",$notifyMsg."回调....");
  
  $lastIndex = strripos($notifyMsg,"|");
  $signMsg = substr($notifyMsg,$lastIndex+1); //签名信息
  $srcMsg = substr($notifyMsg,0,$lastIndex+1);//原文
  $merID = $this->config->item('merID');
  $fp = stream_socket_client($this->socket, $errno, $errstr, 30);
  $retMsg="";
  //
  if (!$fp) {
   echo "$errstr ($errno)<br />\n";
   log_message("error","$errstr ($errno)<br />\n");
  } else{  
   $in  = "<?xml version='1.0' encoding='gb2312'?>";
   $in .= "<Message>";
   $in .= "<TranCode>".$tranCode."</TranCode>";
   $in .= "<merchantID>".$merID."</merchantID>";
   $in .= "<MsgContent>".$notifyMsg."</MsgContent>";
   $in .= "</Message>";
  fwrite($fp, $in);
    while (!feof($fp)) {
     $retMsg =$retMsg.fgets($fp, 1024); 
    }
    fclose($fp);
  }
  //解析返回xml
  $dom = new DOMDocument;
  $dom->loadXML($retMsg); 
  $retCode = $dom->getElementsByTagName('retCode');
  $retCode_value = $retCode->item(0)->nodeValue;
  $errMsg = $dom->getElementsByTagName('errMsg');
  $errMsg_value = $errMsg->item(0)->nodeValue;
  if($retCode_value != '0')
  {
   log_message("error","交易错误信息:" .$errMsg_value."<br>");
   return false;
  }else{
   $arr = preg_split("/\|{1,}/",$srcMsg);
   if($arr[9]=="1"){
    return $this->updateBill($arr[1]);
   }
   log_message("error","交易失败:".$arr[13]."<br/>");
   return false;
  } 
 }
 private function updateBill($billNo){
  // 更新 订单状态
 }
 //end class
}
2.3 控制器
$this->load->model("Bocom");
 支付方法:
 $this->arrData =$this->Bocom->pay($this->data);
 通知:
   $this->arrData =$this->Bocom->notify();

标签:[!--infotagslink--]

您可能感兴趣的文章: