作者归档:admin

PHP源码阅读笔记五:array 数组的创建

PHP源码阅读笔记五:array 数组的创建

在PHP的调试环境中使用cli执行PHP文件
一步一步跟踪代码,由于对C和词法分析不熟悉
所使用PHP文件如下:

1
2
3
 <?PHP
$a = array(1, 2, 3);
var_dump($a);

代码简单跟踪如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
 
===>php_execute_script(&file_handle TSRMLS_CC);     //php_cli.c line1130
==> retval = (zend_execute_scripts(ZEND_REQUIRE TSRMLS_CC, NULL, 3, prepend_file_p, primary_file, append_file_p) == SUCCESS);    //    main.c 2023行
==> EG(active_op_array) = zend_compile_file(file_handle, type TSRMLS_CC);      //    zend.c 1126行
==> compiler_result = zendparse(TSRMLS_C);   //    zend_language_scanner.c  3420行
==> zend-language_parse.c     2773==>case 382:     { zend_do_init_array(&(yyval), &(yyvsp[(1) - (1)]), NULL, 0 TSRMLS_CC); }    //    zend_language_parser.c  4689行
    ==>void zend_do_init_array(znode *result, znode *expr, znode *offset, zend_bool is_ref TSRMLS_DC)    //    zend_compile.c 3348行
 
 
 
==>case 380:    { zend_do_add_array_element(&(yyval), &(yyvsp[(3) - (3)]), NULL, 0 TSRMLS_CC); }//    zend_language_parser.c  4684行
    ==>void zend_do_add_array_element(znode *result, znode *expr, znode *offset, zend_bool is_ref TSRMLS_DC)    //    zend_compile.c 3371行

在代码跟踪过程中,发现当PHP的源码生成语法树时,遇到array和第一个数字时是没有任何有关数组的操作的,当解析到1后面的逗号时才会调用zend_do_init_array函数,创建数组

以上只是一个跟踪的过程,对于代码没有解释,由于自身水平有限,对于词法分析和语法分析了解不多,
另:如果PHP程序的最后一行代码后面没有回车换行,在读取源码文件时会看到一堆乱码

待续…

MySQL中的排序

MySQL中的排序

曾经以为filesort是文件排序,后来知道这仅仅是一个排序,文件只是路人甲而已
前些日子从china-pub上买了《Mysql核心内幕》,当浏览到第4章时,以前对MySQL的排序,join buffer不理解的地方,忽然觉得懂了,只是不知道这个懂了是真懂了还是假懂了。
就如当你从一个梦中醒来,难道你就确认你一定不是在做梦了吗?

说说看了什么吧,
filesort排序算法是将一组记录或元素按照快速排序算法放入到内存缓存,然后这几个内存缓存按合并排序算法排序。(摘自《Mysql核心内幕》第82页)
filesort有两种模式:
1、直接模式,将已经数据完全读取出来,然后进行排序
2、指针模式,先根据过滤条件取出排序字段(sort_key)和可以行指针信息(row_id),根据sort_key排序后,再依据row_id取出取出查询中所请求的其他字段。
第一种算法的优势是减少了数据的二次访问,当然会消耗更多的内存,在算法上来讲是以空间换时间。
MySQL会尽量采用每一种方式,只有在每一种方式不行的情况下才会采用第二种方式(即指针模式)

然后是MySQL的三种排序方法:
1、使用索引排序
2、在单表上使用filesort排序
3、先使用临时表,再使用filesort排序
(摘自《Mysql核心内幕》第83页)

PHP源码阅读笔记四:count函数

PHP源码阅读笔记之count函数

在一些面试或考试中经常会看到count函数的身影,于是一探其究竟

对于非数组的count处理
在其代码中可以看到

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
35
36
37
38
39
40
41
PHP_FUNCTION(count)
{
    zval *array;
    long mode = COUNT_NORMAL;
    if (zend_parse_parameters (ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE)
        return;
    switch (Z_TYPE_P(array)) {
        case IS_NULL:    //    空值处理
            RETURN_LONG(0);
            break;
        case IS_ARRAY:    //    处理数组,包括其是递归
            RETURN_LONG (php_count_recursive (array, mode TSRMLS_CC));
            break;
        case IS_OBJECT: {    
    #ifdef HAVE_SPL
        /* it the object implements Countable we call its count() method */
            zval *retval;
 
            if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Countable TSRMLS_CC)) {
                zend_call_method_with_0_params(&array, NULL, NULL, "count", &retval);
                if (retval) {
                    convert_to_long_ex(&retval);
                    RETVAL_LONG(Z_LVAL_P(retval));
                    zval_ptr_dtor(&retval);
                }
            return;
            }
    #endif
        /* if not we return the number of properties (not taking visibility into account) */
            if (Z_OBJ_HT_P(array)->count_elements) {
                RETVAL_LONG(1);
                if (SUCCESS == Z_OBJ_HT(*array)->count_elements(array, &Z_LVAL_P(return_value) TSRMLS_CC)) {
                    return;    
              }
            }
        }
    default:    //    其它情况,如考试中常见的字符串等
        RETURN_LONG(1);
        break;
    }
}

在手册中有说明:
此函数对于对象,如果安装了 SPL,可以通过实现 Countable 接口来调用 count()。该接口只有一个方法 count(),此方法返回 count() 函数的返回值。

对于数组长度的统计,如果mode使用默认值(0),则仅显示第一维数组的长度
如下所示代码

1
2
3
4
5
6
7
8
$arr = array(1, 2, 3);
$arr2 = array($arr, $arr);
echo count($arr2), '<br />';
echo count($arr2, 1);
/*   输出结果:
2
8
*/

如果只是显示第一维数组,则直接返回保存数组的HashTable的nNumOfElements属性即可
其实现的代码为:

1
2
3
4
5
6
7
8
9
//    php_count_recursive函数 array.c 251行
cnt = zend_hash_num_elements(Z_ARRVAL_P(array));
 
ZEND_API int zend_hash_num_elements(HashTable *ht)
{
    IS_CONSISTENT(ht);
 
    return ht->nNumOfElements;
}

如果想直接运行HashTable的一些简单操作,猛击PHP源码中HashTable的简单示例
如果想查看了解数组存储或遍历的方式,猛击鸟哥的深入理解PHP之数组(遍历顺序)

如果启动了递归,即使用count($arr, 1)
则程序会递归调用php_count_recursive函数
针对HashTable,程序会遍历包含这一维数组的双向链表,然后再递归遍历每个节点存储的pData,真到遍历完所有的节点

【感受】
HashTable很强大,如果要计算数组的长度还是调用count函数,重复发明轮子会是一种吃力不讨好的事情!