在PHP编程中,在遍历数组的时候经常需要先计算数组的长度作为循环结束的判断条件,而在PHP里面对数组的操作是很频繁的,因此count也算是一个常用函数,下面研究一下count函数的具体实现。

我在github上有对PHP源码更详细的注解。感兴趣的可以围观一下,给个star。PHP5.4源码注解。可以通过commit记录查看已添加的注解。

count

int count ( mixed $array_or_countable [, int $mode = COUNT_NORMAL ] )

count函数计算数组或者对象里面的所有元素个数。

对于对象来说,如果你安装了SPL扩展,可以通过实现Countable接口来调用count函数。Countable接口有且仅有一个方法Countable::count(),该方法的返回count()函数的返回值。

参数说明

mode

如果参数mode设为COUNT_RECURSIVE(或1),count()会递归地计算该数组。在计算多维数组的时候特别有用。

如果第一个参数不是数组或者实现Countable接口的对象,count函数将返回1。

注意:count函数可以检测递归避免无限循环,但会在遇到无限递归或得到比期望值大的时候返回E_WARNING提示。

运行示例

普通应用

$arr1 = array(1, 2, 3, 4, 5);

多维数组

$arr2 = array('apple', 'banana', array('cat', 'camel'), 'dog');

数字和字符串

$str = "hello world";
$int_val = 1;

普通对象

class User {
    private $name;
    private $address;
}

$user = new User();

array-like对象

    class User extends ArrayObject {
        private $name;

        public function __construct() {
            $this->name = 'hhq';
        }

        public function getName() {
            return $this->name;
        }

        public function count() {
            return 2;
        }

    }

    $user2 = new User();
    

实现Countable接口对象

    class User implements Countable {
        public function count() {
            return 3;
        }
    }

    $user3 = new User();
     

运行步骤

进入switch语句检测参数类型

  如果是NULL,直接返回0

  如果是数组,调用php_count_recursive函数机选数组元素个数

  如果是对象,先检查是否为数组对象(array-like object),如果是,则计算数组对象的数量

  否则,如果对象实现了Countable接口,则调用Countable的count方法

  最后,其他类型比如整型数组或字符串,都返回1。

源码解读

如果是普通数组,count函数会调用php_count_recursive函数实现其功能的运行步骤如下:

如果当前hash Bucket被递归访问的次数大于1,说明重复递归,染回E_WARNING错误

否则计算当前数组层数的数组元素个数

如果有递归参数选项,则继续递归访问

如果参数是对象类型,实现时会先判断handler是否被定义。而handler是PHP内核中对象的结构体,其中包含有count_elements字段,实际上是一个函数。如果某个对象表现得想数组一样,即通常说的array-like object,那么就会执行count_elements函数。具体实现是类继承PHP的ArrayObject,并在类里面实现count函数,具体调用的就是count函数,如果类没有实现count函数,则count返回0,否则返回对象的count函数的返回值。

如果是其他的数据类型
1、字符串

2、数字

3、对象分支中两个if判断都为false的情况,即没有继承ArrayObject且没有实现Countable接口。

这些类型通通返回1。

需要注意的是,如果需要计算的是对象的属性数量,可以先将对象转换成数组,然后调用count函数。如:
$count_value = count((array) $user);

小结

阅读count函数的源码过程中,在其中一步卡住了,就是if (Z_OBJ_HT_P(array)->count_elements)这一步,因为始终无法写出进入这个分支的demo,在网上搜索了很多资料也未果,因此请教了TIPIreeze,最终得到了想要的答案。不懂就要问,哈哈。

原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

如果本文对你有帮助,请点下推荐吧,谢谢^_^

最后再安利一下,我在github有对PHP源码更详细的注解。感兴趣的可以围观一下,给个star。PHP5.4源码注解。可以通过commit记录查看已添加的注解。

更多源码文章,欢迎访问个人主页继续查看:hoohack

[PHP源码阅读]count函数的更多相关文章

  1. [PHP源码阅读]strlen函数

    文章来自:http://www.hoohack.me/2016/02/22/phps-source-analytics-strlen 我在github有对PHP源码更详细的注解.感兴趣的可以围观一下, ...

  2. keystone源码阅读--python函数

    按照setup.sfg文件中[entry_poubts]中的声明前后阅读: 1.cmd.manage:main os.path.join(path,name):连接目录与文件名或目录os.path.e ...

  3. CI框架源码阅读笔记3 全局函数Common.php

    从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...

  4. [PHP源码阅读]trim、rtrim、ltrim函数

    trim系列函数是用于去除字符串中首尾的空格或其他字符.ltrim函数只去除掉字符串首部的字符,rtrim函数只去除字符串尾部的字符. 我在github有对PHP源码更详细的注解.感兴趣的可以围观一下 ...

  5. [PHP源码阅读]explode和implode函数

    explode和implode函数主要用作字符串和数组间转换的操作,比如获取一段参数后根据某个字符分割字符串,或者将一个数组的结果使用一个字符合并成一个字符串输出.在PHP中经常会用到这两个函数,因此 ...

  6. 3 EventTime 事件时间类和TimeNow函数——Live555源码阅读(一)基本组件类

    这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 这里是时间相关类的第三个部分,也是最后一个部分. EventTime 事件时间类 这个类和Dela ...

  7. PHP源码阅读笔记一(explode和implode函数分析)

    PHP源码阅读笔记一一.explode和implode函数array explode ( string separator, string string [, int limit] )此函数返回由字符 ...

  8. 【原】FMDB源码阅读(二)

    [原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...

  9. 【原】FMDB源码阅读(一)

    [原]FMDB源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 说实话,之前的SDWebImage和AFNetworking这两个组件我还是使用过的,但是对于 ...

随机推荐

  1. 懒加载session 无法打开 no session or session was closed 解决办法(完美解决)

           首先说明一下,hibernate的延迟加载特性(lazy).所谓的延迟加载就是当真正需要查询数据时才执行数据加载操作.因为hibernate当中支持实体对象,外键会与实体对象关联起来.如 ...

  2. LeetCode-4MedianofTwoSortedArrays(C#)

    # 题目 4. Median of Two Sorted Arrays There are two sorted arrays nums1 and nums2 of size m and n resp ...

  3. JavaScript中Math对象的方法介绍

    1.比较最值方法 比较最值有两种方法,max() 和 min() 方法. 1.1 max() 方法,比较一组数值中的最大值,返回最大值. var maxnum = Math.max(12,6,43,5 ...

  4. 客户端的验证插件validator

    简单,智能,令人愉悦的表单验证~~~ 官方文档:http://www.niceue.com/validator/ <!DOCTYPE html> <html> <head ...

  5. SQL Server-聚焦UNIOL ALL/UNION查询(二十三)

    前言 本节我们来看看有关查询中UNION和UNION ALL的问题,简短的内容,深入的理解,Always to review the basics. 初探UNION和UNION ALL 首先我们过一遍 ...

  6. mybatis plugins实现项目【全局】读写分离

    在之前的文章中讲述过数据库主从同步和通过注解来为部分方法切换数据源实现读写分离 注解实现读写分离: http://www.cnblogs.com/xiaochangwei/p/4961807.html ...

  7. 浅谈JSP中include指令与include动作标识的区别

    JSP中主要包含三大指令,分别是page,include,taglib.本篇主要提及include指令. include指令使用格式:<%@ include file="文件的绝对路径 ...

  8. PHP 设计模式概述

    一.设计模式(Design pattern)是什么? 设计模式是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. ...

  9. 自定义控件之 圆形 / 圆角 ImageView

    一.问题在哪里? 问题来源于app开发中一个很常见的场景——用户头像要展示成圆的:       二.怎么搞? 机智的我,第一想法就是,切一张中间圆形透明.四周与底色相同.尺寸与头像相同的蒙板图片,盖在 ...

  10. git 命令总结

    1 删除分支 git push origin :branch name(Task_******) //删除远程分支 git branch -D branch name(Task_******)     ...