【PECL】在扩展中实现 autoload

【PECL】在扩展中实现 autoload

摘要

php-8.3.x 用扩展写个框架。想实现类管理器,自动加载,上代码:

PHP代码想这么写

$ws = new \Ziima\Applet();
$ws->import('Ziima', '../base/core');
$ws->runAutoload();

$t = new \Ziima\Template\Context();
print_r($t);

C 代码这么实现

没有文档,硬翻源代码一点点抠出来这么个思路,能用。

ZEND_METHOD(Ziima_Applet, runAutoload) {
    zval *this       = getThis();
    zend_string *req = NULL;

    ZEND_PARSE_PARAMETERS_START(0, 1)
    Z_PARAM_OPTIONAL
    Z_PARAM_STR(req)
    ZEND_PARSE_PARAMETERS_END();

    //[1] 没有参数 , 或者 this._auto 未设置,判断是PHP调用 runAutoload 来注册
    zval *_auto = zend_read_property(ce_Ziima_Applet, Z_OBJ_P(this), ZEND_STRL("_auto"), true, NULL);
    if (_auto == NULL || Z_TYPE_P(_auto) != IS_OBJECT) {
        zval           cu, par_r;
        zend_function *fn = zend_hash_str_find_ptr_lc(&Z_OBJCE_P(this)->function_table, ZEND_STRL("runAutoload"));
        zend_create_closure(&cu, fn, ce_Ziima_Applet, ce_Ziima_Applet, this);

        zend_fcall_info fci;
        fci.size         = sizeof(zend_fcall_info);
        fci.object       = NULL;
        fci.named_params = NULL;
        fci.retval       = &par_r;
        fci.param_count  = 3;
        fci.params       = ecalloc(sizeof(zval), 3);
        ZVAL_COPY_VALUE(fci.params, &cu);
        ZVAL_TRUE(fci.params + 1);
        ZVAL_TRUE(fci.params + 2);
        ZVAL_STRING(&fci.function_name, "spl_autoload_register");
        if (zend_call_function(&fci, NULL) != SUCCESS) {
            zval_delref_p(&cu);
            RETURN_FALSE;
        }
        if (Z_TYPE(par_r) != IS_TRUE) {
            zval_delref_p(&cu);
            RETURN_FALSE;
        }
        zend_update_property(ce_Ziima_Applet, Z_OBJ_P(this), ZEND_STRL("_auto"), &cu);
        RETURN_TRUE;
    }

    // [2] 有参数进来,则认为是被 spl_autoload_register 调用的
    if (req == NULL) {
        RETURN_FALSE;
    }

    zval *_vendor = zend_read_property(ce_Ziima_Applet, Z_OBJ_P(this), ZEND_STRL("_vendor"), true, NULL);
    if (_vendor == NULL || Z_TYPE_P(_vendor) != IS_ARRAY)
        RETURN_FALSE;
    if (zend_array_count(Z_ARR_P(_vendor)) < 1)
        RETURN_FALSE;
    // [3] 类加载器只能处理有命名空间的
    if (!nstr_contains(req->val, req->len, '\\'))
        RETURN_FALSE;
    vector_object *vreq   = vector_split_ex(req->val, req->len, '\\', VCONF_AUTO_TRIM | VCONF_DENY_EMPTY);
    vector_item   *ve     = vector_first(vreq);
    zend_string   *ns_req = zend_string_init(ve->key.val, ve->key.len, false);
    zend_string   *dp_req = NULL;
    zend_long      h      = 0;
    zend_string   *k      = NULL;
    zval          *v      = NULL;
    // [4] 找登记路径
    ZEND_HASH_MAP_FOREACH_KEY_VAL(Z_ARR_P(_vendor), h, k, v)
    if (k->len != ns_req->len)
        continue;
    if (strncasecmp(k->val, ns_req->val, ns_req->len) == 0) {
        dp_req = zend_string_dup(Z_STR_P(v), false);
        break;
    }
    ZEND_HASH_FOREACH_END();
    if (dp_req == NULL) {
        vector_destroy(vreq);
        zend_string_release(ns_req);
        RETURN_FALSE;
    }

    // [5] 拼路径
    buf_string tmp;
    bstr_init(&tmp, dp_req->len + req->len + 64);

    bstr_append(&tmp, dp_req->val);
    if (tmp.val[dp_req->len - 1] == '/') {
        tmp.val[dp_req->len - 1] = 0;
        tmp.len--;
    }
    VECTOR_FOREACH_BEGIN(vreq, h, ve)
    if (h == 1)
        continue;
    bstr_append_char(&tmp, '/');
    bstr_append_ex(&tmp, ve->key.val, ve->key.len);
    VECTOR_FOREACH_END();
    vector_destroy(vreq);
    bstr_append(&tmp, ".php");

    // [6] 查文件
    zend_string_release(ns_req);
    zend_string_release(dp_req);
    if (access(tmp.val, F_OK) != 0) {
        bstr_free(&tmp);
        RETURN_FALSE;
    }
    // kdebug("load %s from %s", ns_req->val, tmp.val);
    // [7] 用 eval + include_once 包含
    bstr_append(&tmp, "');");
    const char *ps = "include_once('";
    uint32_t    ls = strlen(ps);
    memmove(tmp.val + ls, tmp.val, tmp.len);
    memcpy(tmp.val, ps, ls);
    if (zend_eval_string(tmp.val, NULL, "ziima_autoload_script") != SUCCESS) {
        bstr_free(&tmp);
        RETURN_FALSE;
    }
    bstr_free(&tmp);
    RETURN_TRUE;
}

相关推荐

  1. PECL扩展实现 autoload

    2024-06-06 21:12:03       35 阅读
  2. 面向对象编程Perl实现:解锁Perl的OOP潜力

    2024-06-06 21:12:03       28 阅读
  3. pear + pecl 安装php扩展

    2024-06-06 21:12:03       33 阅读
  4. Perl的文件系统守卫:实现自定义访问控制

    2024-06-06 21:12:03       29 阅读
  5. Perl的设计模式革新:命令模式的实现与应用

    2024-06-06 21:12:03       24 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-06 21:12:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-06 21:12:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-06-06 21:12:03       82 阅读
  4. Python语言-面向对象

    2024-06-06 21:12:03       91 阅读

热门阅读

  1. Opengrok代码在线查看平台

    2024-06-06 21:12:03       32 阅读
  2. leetcode部分简单题题解

    2024-06-06 21:12:03       25 阅读
  3. TP6 事件绑定、监听、订阅

    2024-06-06 21:12:03       28 阅读
  4. 使用Keepalived提高吞吐量和负载均衡ip_hash.

    2024-06-06 21:12:03       30 阅读
  5. 找到自己的前提是认识自己

    2024-06-06 21:12:03       26 阅读
  6. Android Studio SharedPreferences的使用

    2024-06-06 21:12:03       29 阅读
  7. 使用Scapy框架分析HTTP流量

    2024-06-06 21:12:03       31 阅读
  8. 无人机反制软硬手段

    2024-06-06 21:12:03       30 阅读
  9. 单例模式(C语言)

    2024-06-06 21:12:03       32 阅读
  10. 自学之路Flutter使用Provider进行状态管理

    2024-06-06 21:12:03       31 阅读