浅析PHP中Collection 类的设计


Posted in PHP onJune 21, 2013

用.net开发已经很多年了,最近接触到php,发现php也很好玩。不过发现它里面没有集合Collection类,只有数组,并且数组很强。这里我用数组来包装成一个集合Collection,代码如下:

class Collection{ 
    private $_members=array();     public  function addItem($obj,$key=null) 
    { 
        if($key) 
        { 
            if(isset($this->_members[$key])) 
            { 
                throw  new exception("Key \"$key\" already in use!"); 
            } 
            else
            { 
                $this->_members[$key]=$obj; 
            } 
        } 
        else
        { 
            $this->_members[]=$obj; 
        } 
    } 
    public function removeItem($key) 
    { 
        if(isset($this->_members[$key])) 
        { 
            unset($this->_members[$key]); 
        } 
        else
        { 
            throw new exception("Invalid Key \"$key\"!"); 
        } 
    } 
    public function getItem($key) 
    { 
        if(isset($this->_members[$key])) 
        { 
            return $this->_members[$key]; 
        } 
        else
        { 
            throw new  exception("Invalid Key \"$key\"!"); 
        } 
    } 
    public function Keys() 
    { 
        return array_keys($this->_members); 
    } 
    public function legth() 
    { 
        return sizeof($this->_members); 
    } 
    public function exists($key) 
    { 
        return (isset($this->_members[$key])); 
    } 
}

现在我们来测试一下这个集合是否好用。
我们首先建立一个集合元素类Course:
class  Course 
{ 
    private $_id; 
    private $_courseCode; 
    private $_name;   public function __construct($id,$courseCode,$name) 
    { 
        $this->_id=$id; 
        $this->_courseCode=$courseCode; 
        $this->_name=$name; 
    } 
    public function getName() 
    { 
        return $this->_name; 
    } 
    public function getID() 
    { 
        return $this->_id; 
    } 
    public function getCourseCode() 
    { 
        return $this->_courseCode; 
    } 
    public function __toString() 
    { 
        return $this->_name; 
    } 
}

测试代码如下:
$courses=new Collection();
$courses->addItem(new Course(1, "001", "语文"),1);
$courses->addItem(new Course(2, "002", "数学"),2);
$obj=$courses->getItem(1);
print $obj;
我想这个集合类应该可以满足我们平日开发的需求了吧。
可是我们现在。net里面有个对象延迟加载,举个例子来说吧,假如现在有Student这个对象,它应该有很多Course,但是我们希望在访问Course之前Course是不会加载的。也就是说在实例化Student的时候Course个数为0,当我们需要Course的时候它才真正从数据库读取相应数据。就是需要我们把Collection做成惰性实例化。
修改后的Collection代码如下:
class Collection {
  private $_members = array();    //collection members
  private $_onload;               //holder for callback function
  private $_isLoaded = false;     //flag that indicates whether the callback
                                  //has been invoked
  public function addItem($obj, $key = null) {
    $this->_checkCallback();      //_checkCallback is defined a little later    if($key) {
      if(isset($this->_members[$key])) {
        throw new KeyInUseException("Key \"$key\" already in use!");
      } else {
        $this->_members[$key] = $obj;
      }
    } else {
      $this->_members[] = $obj;
    }
  }
  public function removeItem($key) {
    $this->_checkCallback();
    if(isset($this->_members[$key])) {
      unset($this->_members[$key]);
    } else {
      throw new KeyInvalidException("Invalid key \"$key\"!");
    }  
  }
  public function getItem($key) {
    $this->_checkCallback();
    if(isset($this->_members[$key])) {
      return $this->_members[$key];
    } else {
      throw new KeyInvalidException("Invalid key \"$key\"!");
    }
  }
  public function keys() {
    $this->_checkCallback();
    return array_keys($this->_members);
  }
  public function length() {
    $this->_checkCallback();
    return sizeof($this->_members);
  }
  public function exists($key) {
    $this->_checkCallback();
    return (isset($this->_members[$key]));
  }
  /**
   * Use this method to define a function to be 
   * invoked prior to accessing the collection.  
   * The function should take a collection as a 
   * its sole parameter.
   */
  public function setLoadCallback($functionName, $objOrClass = null) {
    if($objOrClass) {
      $callback = array($objOrClass, $functionName);
    } else {
      $callback = $functionName;
    }
    //make sure the function/method is valid
    if(!is_callable($callback, false, $callableName)) {
      throw new Exception("$callableName is not callable " . 
                          "as a parameter to onload");
      return false;
    }
    $this->_onload = $callback;
  }
  /**
   * Check to see if a callback has been defined and if so,
   * whether or not it has already been called.  If not,
   * invoke the callback function.
   */
  private function _checkCallback() {
    if(isset($this->_onload) && !$this->_isLoaded) {
      $this->_isLoaded = true;
      call_user_func($this->_onload, $this);
    }
  }
}

所需的Student如下:
class CourseCollection extends Collection { 
 public function addItem(Course $obj,$key=null) { 
        parent::addItem($obj,$key); 
    } 
} 
class Student{ 
    private $_id; 
    private $_name; 
    public $course;     public  function __construct($id,$name) 
    { 
        $this->_id=$id; 
        $this->_name=$name; 
        $this->course=new CourseCollection(); 
        $this->course->setLoadCallback('loadCourses',$this); 
    } 
    public function getName() 
    { 
        return $this->_name; 
    } 
    public function getID() 
    { 
        return $this->_id; 
    } 
    public function __toString() 
    { 
        return $this->_name; 
    } 
    public function loadCourses(Collection $col) 
    { 
        $col->addItem(new Course(1, "001", "语文"),1); 
        $col->addItem(new Course(2, "002", "数学"),2); 
    } 
}

调用代码如下:
$student=new Student(1, "majiang");
print $student->getName();
print $student->course->getItem(1);
PHP 相关文章推荐
php Ajax乱码
Apr 09 PHP
PHP中$_SERVER的详细参数与说明介绍
Oct 26 PHP
PHP会话处理的10个函数
Aug 11 PHP
PHP+MySQL存储数据常见中文乱码问题小结
Jun 13 PHP
如何正确配置Nginx + PHP
Jul 15 PHP
PHP 闭包详解及实例代码
Sep 28 PHP
php连接微软MSSQL(sql server)完全攻略
Nov 27 PHP
PHP实现移除数组中为空或为某值元素的方法
Jan 07 PHP
PHP实现的堆排序算法详解
Aug 17 PHP
Laravel中日期时间处理包Carbon的简单使用
Sep 21 PHP
PHP实现的防止跨站和xss攻击代码【来自阿里云】
Jan 29 PHP
laravel csrf排除路由,禁止,关闭指定路由的例子
Oct 21 PHP
解析PHP无限级分类方法及代码
Jun 21 #PHP
PHP 循环删除无限分类子节点的实现代码
Jun 21 #PHP
解析左右值无限分类的实现算法
Jun 20 #PHP
解析thinkphp的左右值无限分类
Jun 20 #PHP
PHP 清空varnish 缓存的详解(包括指定站点下的)
Jun 20 #PHP
PHP array_multisort() 函数的深入解析
Jun 20 #PHP
PHP操作MongoDB GridFS 存储文件的详解
Jun 20 #PHP
You might like
PHP中显示格式化的用户输入
2006/10/09 PHP
E路文章系统PHP
2006/12/11 PHP
Php Mssql操作简单封装支持存储过程
2009/12/11 PHP
用PHP为SHOPEX增加日志功能代码
2010/07/02 PHP
php cc攻击代码与防范方法
2012/10/18 PHP
PHP数据过滤的方法
2013/10/30 PHP
PHP针对多用户实现更换头像功能
2016/09/04 PHP
php is_executable判断给定文件名是否可执行实例
2016/09/26 PHP
PHP基于DateTime类解决Unix时间戳与日期互转问题【针对1970年前及2038年后时间戳】
2018/06/13 PHP
JQuery 选择器 xpath 语法应用
2010/05/13 Javascript
JQuery筛选器全系列介绍
2013/08/27 Javascript
深入探讨JavaScript String对象
2015/03/09 Javascript
javascript处理a标签超链接默认事件的方法
2015/06/29 Javascript
javascript实现网页背景烟花效果的方法
2015/08/06 Javascript
基于javascript实现最简单的选项卡切换效果
2016/05/16 Javascript
学习JavaScript图片预加载模块
2016/11/07 Javascript
微信小程序分页加载的实例代码
2017/07/11 Javascript
pycharm 使用心得(五)断点调试
2014/06/06 Python
Python列表常见操作详解(获取,增加,删除,修改,排序等)
2019/02/18 Python
python 定时器,轮询定时器的实例
2019/02/20 Python
自定义django admin model表单提交的例子
2019/08/23 Python
matplotlib 使用 plt.savefig() 输出图片去除旁边的空白区域
2021/01/05 Python
S’well Bottle保温杯官网:绝缘不锈钢水瓶
2018/05/09 全球购物
西班牙在线宠物食品和配件商店:bitiba
2019/10/11 全球购物
哪些情况下不应该使用索引
2015/07/20 面试题
如何清空Session
2015/02/23 面试题
教师职位说明书
2014/07/29 职场文书
2014年个人师德工作总结
2014/12/04 职场文书
教师教育教学随笔
2015/08/15 职场文书
初中生物教学反思
2016/02/20 职场文书
《工作是最好的修行》读后感3篇
2019/12/13 职场文书
雄兵连:第三季先行图公开,天使恶魔联合,银河之力的新力量
2021/06/11 国漫
redis requires ruby version2.2.2的解决方案
2021/07/15 Redis
能用CSS实现的就不要麻烦JavaScript了
2021/10/05 HTML / CSS
MySQL运行报错:“Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre”解决方法
2022/06/14 MySQL
关于Redis的主从复制及哨兵问题
2022/06/16 Redis