search
HomeBackend DevelopmentPHP Tutorial[Translation] [php extension development and embedded] Chapter 10 - Objects of php4

Objects of php4

Once upon a time, in very early versions, php did not support any object-oriented programming syntax. The Zend engine (ZE1) was introduced in php4, and several new features appeared , including object data types.

The evolution of php object types

The first object-oriented programming (OOP) support only implemented the semantics of object associations. Use a php kernel developer In other words, "php4 objects just bind an array and some methods together". It is the php object you want to study now.

The second major version release of the Zend engine (ZE2) is In PHP5, some new features were introduced in PHP's OOP implementation. For example, properties and methods can use access modifiers to mark their visibility outside your class definition, and overloading of functions can be used to define internal language constructs. For custom behaviors, interfaces can be used to implement API standardization between call chains of multiple classes. When you study Chapter 11 "php5 objects", you will establish these features by implementing these features in the class definition of php5. Cognition of knowledge.

Implementation class

Before entering the world of OOP, we need to travel lightly. Therefore, please restore your extension to Chapter 5 "Your First Extension" "The skeleton form just built in.

In order to be independent from your original exercise, you can name this version sample2. Put the following three files into ext/sample2 of your PHP source code Directory:

config.m4

PHP_ARG_ENABLE(sample2,  
  [Whether to enable the "sample2" extension],  
  [  enable-sample2       Enable "sample2" extension support])  
  
if test $PHP_SAMPLE2 != "no"; then  
  PHP_SUBST(SAMPLE2_SHARED_LIBADD)  
  PHP_NEW_EXTENSION(sample2, sample2.c, $ext_shared)  
fi

php_saple2.h

#ifndef PHP_SAMPLE2_H  
/* Prevent double inclusion */  
#define PHP_SAMPLE2_H  
  
/* Define Extension Properties */  
#define PHP_SAMPLE2_EXTNAME    "sample2"  
#define PHP_SAMPLE2_EXTVER    "1.0"  
  
/* Import configure options 
   when building outside of 
   the PHP source tree */  
#ifdef HAVE_CONFIG_H  
#include "config.h"  
#endif  
  
/* Include PHP Standard Header */  
#include "php.h"  
  
/* Define the entry point symbol 
 * Zend will use when loading this module 
 */  
extern zend_module_entry sample2_module_entry;  
#define phpext_sample2_ptr &sample2_module_entry  
  
#endif /* PHP_SAMPLE2_H */

sample2.c

#include "php_sample2.h"  
  
static function_entry php_sample2_functions[] = {  
    { NULL, NULL, NULL }  
};  
  
PHP_MINIT_FUNCTION(sample2)  
{  
    return SUCCESS;  
}  
  
zend_module_entry sample2_module_entry = {  
#if ZEND_MODULE_API_NO >= 20010901  
    STANDARD_MODULE_HEADER,  
#endif  
    PHP_SAMPLE2_EXTNAME,  
    php_sample2_functions,  
    PHP_MINIT(sample2),  
    NULL, /* MSHUTDOWN */  
    NULL, /* RINIT */  
    NULL, /* RSHUTDOWN */  
    NULL, /* MINFO */  
#if ZEND_MODULE_API_NO >= 20010901  
    PHP_SAMPLE2_EXTVER,  
#endif  
    STANDARD_MODULE_PROPERTIES  
};  
  
#ifdef COMPILE_DL_SAMPLE2  
ZEND_GET_MODULE(sample2)  
#endif

Now, just like in Chapter 5, you You can execute phpize, ./configure, make to build your sample2.so extension module.

Your previous config.w32 can work normally if you make the same modifications as the config.m4 given here.

Define class entries

In user space, define a class as follows:

<?php  
class Sample2_FirstClass {  
}  
?>

As you can no doubt guess, implementing this in an extension is a bit difficult. First, you need to define a zend_class_entry pointer in your source code file, just like you defined int le_sample_descriptor in the previous chapter:

zend_class_entry *php_sample2_firstclass_entry;

Now, you can initialize and register the class in the MINIT function.

PHP_MINIT_FUNCTION(sample2)  
{  
    zend_class_entry ce; /* 临时变量 */  
  
    /* 注册类 */  
    INIT_CLASS_ENTRY(ce, "Sample2_FirstClass", NULL);  
    php_sample2_firstclass_entry =  
            zend_register_internal_class(&ce TSRMLS_CC);  
  
    return SUCCESS;  
}

Build this extension, test get_declared_classes(), and you will see that Sample2_FirstClass is now available in user space.

Defining the implementation of the method

At this point, you What is implemented is just a stdClass, of course it is available. But actually you want your class to do something.

To achieve this goal, you need to go back to the other things you learned in Chapter 5 A knowledge point. Replace the NULL parameter passed to INIT_CLASS_ENTRY() with php_sample2_firstclass_functions, and define this structure directly above the MINIT function as follows:

static function_entry php_sample2_firstclass_functions[] = {  
    { NULL, NULL, NULL }  
};

Does it look familiar? Of course. This is the same as the process function you originally defined. The structure of The name is zif_method1, which may potentially conflict with other method1() implementations. For the namespace safety of the function, we use the class name as the prefix of the method name.

PHP_FALIAS(method1, Sample2_FirstClass_method1, NULL) format It's possible; but it's a bit unintuitive, and you may look back at the code later and wonder, "Why didn't you use PHP_FE()?"

Now, you have attached a function list to the class has been defined, it’s time to define some methods. Create the following function on the php_sample2_firstclass_functions structure:

PHP_NAMED_FE(method1, PHP_FN(Sample2_FirstClass_method1), NULL)

Correspondingly, add a PHP_NAMED_FE() entry to its function list:

PHP_FUNCTION(Sample2_FirstClass_countProps)  
{  
    RETURN_LONG(zend_hash_num_elements(Z_OBJPROP_P(getThis())));  
}

It should be noted that the function names exposed to user space here are all lowercase. In order to ensure that method and function names are case-insensitive, internal functions are required to give names in all lowercase.

The only new element here is getThis(). In all PHP versions, it will be parsed as a macro, and the expansion is this_ptr. This_ptr is essentially the same as $this in user space object methods. . If there is no available object instance, such as the method is called statically, getThis() returns NULL.

The data return semantics of object methods are consistent with those of procedural functions, and parameter acceptance and arg_info are the same set of things.

static function_entry php_sample2_firstclass_functions[] = {  
    PHP_NAMED_FE(countprops,  
            PHP_FN(Sample2_FirstClass_countProps), NULL)  
    { NULL, NULL, NULL }  
};

Constructor

Your class constructor can be implemented like any other ordinary class method, and its naming follows the same rules. The special thing is that you need to name the constructor as Class name. The other two ZE1 magic methods __sleep() and __wakeup() can also be implemented in this way.

Inheritance

In php4, inheritance between internal objects is not Perfect, it is best to avoid using it. If you really must inherit other objects, you need to copy the following ZE1 code:

PHP_FUNCTION(Sample2_FirstClass_sayHello)  
{  
    char *name;  
    int name_len;  
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",  
                        &name, &name_len) == FAILURE) {  
        RETURN_NULL();  
    }  
    php_printf("Hello");  
    PHPWRITE(name, name_len);  
    php_printf("!\nYou called an object method!\n");  
    RETURN_TRUE;  
}

Define such a function, you can call it under zend_register_internal_class in MINIT:

void php_sample2_inherit_from_class(zend_class_entry *ce,  
                        zend_class_entry *parent_ce) {  
    zend_hash_merge(&ce->function_table,  
            &parent_ce->function_table, (void (*)(void *))function_add_ref,  
            NULL, sizeof(zval*), 0);  
    ce->parent = parent_ce;  
    if (!ce->handle_property_get) {  
        ce->handle_property_get =  
                parent_ce->handle_property_get;  
    }  
    if (!ce->handle_property_set) {  
        ce->handle_property_set =  
                parent_ce->handle_property_set;  
    }  
    if (!ce->handle_function_call) {  
        ce->handle_function_call =  
                parent_ce->handle_function_call;  
    }  
    if (!zend_hash_exists(&ce->function_table,  
                ce->name, ce->name_length + 1)) {  
        zend_function *fe;  
        if (zend_hash_find(&parent_ce->function_table,  
                parent_ce->name, parent_ce->name_length + 1,  
                (void**)fe) == SUCCESS) {  
            zend_hash_update(&ce->function_table,  
                ce->name, ce->name_length + 1,  
                fe, sizeof(zend_function), NULL);  
            function_add_ref(fe);  
        }  
    }  
}

Although this style of inheritance can work, inheritance in ZE1 should still be avoided because it was not designed to handle inheritance of internal objects. For most OOP practices in PHP, ZE2 and its revised object model is robust and encourages all OOP related tasks to be handled directly using it.

Work with Examples

和其它用户空间变量一样, 对象存储在zval *容器中. 在ZE1中, zval *包含了一个HashTable *用于保存属性, 以及一个zend_class_entry *指针, 指向类的定义. 在ZE2中, 这些值被一个句柄表替代, 增加了一个数值的对象ID, 它和资源ID的用法类似.

很幸运, ZE1和ZE2的这些差异被第2章"变量的里里外外"中介绍的Z_*()族宏隐藏了, 因此在你的扩展中不需要关心这些. 下表10.1列出了两个ZE1的宏, 与非OOP的相关宏一致, 它们也有对应的_P和_PP版本, 用来处理一级或两级间访.

[Translation] [php extension development and embedded] Chapter 10 - Objects of php4

创建实例

大部分时间, 你的扩展都不需要自己创建实例. 而是用户空间调用new关键字创建实例并调用你的类构造器.

但你还是有可能需要创建实例, 比如在工厂方法中, ZEND_API中的object_init_ex(zval *val, zend_class_entry *ce)函数可以用于将对象实例初始化到变量中.

要注意, object_init_ex()函数并不会调用构造器. 当在内部函数中实例化对象时, 构造器必须手动调用. 下面的过程函数重演了new关键字的功能逻辑:

PHP_FUNCTION(sample2_new)  
{  
    int argc = ZEND_NUM_ARGS();  
    zval ***argv = safe_emalloc(sizeof(zval**), argc, 0);  
    zend_class_entry *ce;  
    if (argc == 0 ||  
        zend_get_parameters_array_ex(argc, argv) == FAILURE) {  
        efree(argv);  
        WRONG_PARAM_COUNT;  
    }  
    /* 第一个参数是类名 */  
    SEPARATE_ZVAL(argv[0]);  
    convert_to_string(*argv[0]);  
    /* 类名存储为小写 */  
    php_strtolower(Z_STRVAL_PP(argv[0]), Z_STRLEN_PP(argv[0]));  
    if (zend_hash_find(EG(class_table),  
            Z_STRVAL_PP(argv[0]), Z_STRLEN_PP(argv[0]) + 1,  
            (void**)&ce) == FAILURE) {  
        php_error_docref(NULL TSRMLS_CC, E_WARNING,  
            "Class %s does not exist.",  
            Z_STRVAL_PP(argv[0]));  
        zval_ptr_dtor(argv[0]);  
        efree(argv);  
        RETURN_FALSE;  
    }  
    object_init_ex(return_value, ce);  
    /* 如果有构造器则调用, 额外的参数将传递给构造器 */  
    if (zend_hash_exists(&ce->function_table,  
            Z_STRVAL_PP(argv[0]),Z_STRLEN_PP(argv[0]) + 1)) {  
        /* 对象有构造器 */  
        zval *ctor, *dummy = NULL;  
  
        /* 构造器名字是类名 */  
        MAKE_STD_ZVAL(ctor);  
        array_init(ctor);  
        zval_add_ref(argv[0]);  
        add_next_index_zval(ctor, *argv[0]);  
        zval_add_ref(argv[0]);  
        add_next_index_zval(ctor, *argv[0]);  
        if (call_user_function_ex(&ce->function_table,  
                NULL, ctor,  
                &dummy, /* 不关心返回值 */  
                argc - 1, argv + 1, /* 参数 */  
                0, NULL TSRMLS_CC) == FAILURE) {  
            php_error_docref(NULL TSRMLS_CC, E_WARNING,  
                 "Unable to call constructor");  
        }  
        if (dummy) {  
            zval_ptr_dtor(&dummy);  
        }  
        zval_ptr_dtor(&ctor);  
    }  
    zval_ptr_dtor(argv[0]);  
    efree(argv);  
}

不要忘了在php_sample2_functions中增加一个引用. 它是你的扩展的过程函数列表, 而不是类方法的列表. 为了使用php_strtolower()函数, 还需要增加#include "ext/standard/php_string.h".

这个函数是目前你实现的最复杂的一个, 其中有几个全新的特性. 首先就是SEPARATE_ZVAL(), 实际上它的功能你已经实现过很多次, 利用zval_copy_ctor()赋值值到一个临时的结构体, 避免修改原始的内容. 不过它是一个宏版本的封装.

php_strtolower()用于将类名转换为小写, 这样做是为了达到php类名和函数名不区分大小写的目的. 这只是附录B中列出的众多PHPAPI工具函数的其中一个.

EG(class_table)是一个全局变量, 所有的zend_class_entry定义都注册到它里面. 要注意的是在ZE1(php4)中这个HashTable存储了一级间访的zend_class_entry *结构体. 而在ZE2(php5)中, 它被存储为两级间访. 这应该不会是一个问题, 因为对这个HashTable的直接访问并不常见, 但知道这一点总归是有好处的.

call_user_function_ex()是你将在第20章"高级嵌入式"中看到的ZENDAPI调用的一部分. 这里你将从zend_get_parameters_ex()接收到的zval **参数栈第一个元素拿走, 这样做就是为了原封不动的将剩余的参数传递给构造器.

译注: 原著中的代码在译者的环境(php-5.4.9)中不能运行, 需要将zend_class_entry *ce修改为二级间访. 下面给出译者测试通过的代码.

PHP_FUNCTION(sample_new)  
{  
    int                 argc    = ZEND_NUM_ARGS();  
    zval                ***argv = safe_emalloc(sizeof(zval **), argc, 0);   
    zend_class_entry    **ce;       /* 译注: 这里在译者的环境(php-5.4.9)是二级间访 */  
  
    /* 数组方式读取所有传入参数 */  
    if ( argc == 0 ||    
            zend_get_parameters_array_ex(argc, argv) == FAILURE ) {   
        efree(argv);  
        WRONG_PARAM_COUNT;  
    }     
  
    /* 隔离第一个参数(隔离为了使下面的类型转换不影响原始数据) */  
    SEPARATE_ZVAL(argv[0]);  
    /* 将第一个参数转换为字符串类型, 并转为小写(因为php的类名是不区分大小写的) */  
    convert_to_string(*argv[0]);  
    php_strtolower(Z_STRVAL_PP(argv[0]), Z_STRLEN_PP(argv[0]));  
    /* 在类的HashTable中查找提供的类是否存在, 如果存在, ce中就得到了对应的zend_class_entry * */  
    if ( zend_hash_find(EG(class_table), Z_STRVAL_PP(argv[0]), Z_STRLEN_PP(argv[0]) + 1, (void **)&ce) == FAILURE ) {   
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Class %s does not exist.", Z_STRVAL_PP(argv[0]));  
        zval_ptr_dtor(argv[0]);  
        efree(argv);  
        RETURN_FALSE;  
    }     
  
    /* 将返回值初始化为查找到的类的对象 */  
    object_init_ex(return_value, *ce);  
    /* 检查类是否有构造器 */  
    if ( zend_hash_exists(&(*ce)->function_table, Z_STRVAL_PP(argv[0]), Z_STRLEN_PP(argv[0]) + 1) ) {   
        zval    *ctor, *dummy = NULL;  
  
        /* 将ctor构造为一个数组, 对应的用户空间形式为: array(argv[0], argv[0]),  
         * 实际上对应于用户空间调用类的静态方法时$funcname的参数形式: 
         * array(类名, 方法名) 
         */  
        MAKE_STD_ZVAL(ctor);  
        array_init(ctor);  
        zval_add_ref(argv[0]);  
        add_next_index_zval(ctor, *argv[0]);  
        zval_add_ref(argv[0]);  
        add_next_index_zval(ctor, *argv[0]);  
        /* 调用函数 */  
        if ( call_user_function_ex(&(*ce)->function_table, NULL, ctor, &dummy, argc - 1, argv + 1, 0, NULL TSRMLS_CC) == FAILURE ) {   
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call constructor");  
        }     
        /* 如果有返回值直接析构丢弃 */  
        if ( dummy ) {  
            zval_ptr_dtor(&dummy);  
        }  
        /* 析构掉临时使用(用来描述所调用方法名)的数组 */  
        zval_ptr_dtor(&ctor);  
    }  
    /* 析构临时隔离出来的第一个参数(类名) */  
    zval_ptr_dtor(argv[0]);  
    /* 释放实参列表空间 */  
    efree(argv);  
}

接受实例

有时你的函数或方法需要接受用户空间的对象参数. 对于这种目的, zend_parse_parameters()提供了两种格式的修饰符. 第一种是o(小写字母o), 它将验证传递的参数是否是对象, 并将它设置到传递的zval **中. 下面是这种方式的一个简单的用户空间函数示例, 它返回传入对象的类名.

PHP_FUNCTION(sample2_class_getname)  
{  
    zval *objvar;  
    zend_class_entry *objce;  
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o",  
                                &objvar) == FAILURE) {  
        RETURN_NULL();  
    }  
    objce = Z_OBJCE_P(objvar);  
    RETURN_STRINGL(objce->name, objce->name_length, 1);  
}

第二种修饰符是O(大写字母O), 它不仅允许zend_parse_parameters()验证zval *的类型, 还可以验证所传递对象的类. 要做到这一点, 就需要传递一个zval **容易以及一个zend_class_entry *用来验证, 比如下面的实现就期望传入的是Sample2_FirstClass类的实例:

PHP_FUNCTION(sample2_reload)  
{  
    zval *objvar;  
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O",  
        &objvar, php_sample2_firstclass_entry) == FAILURE) {  
        RETURN_NULL();  
    }  
    /* 调用假想的"reload"函数 */  
    RETURN_BOOL(php_sample2_fc_reload(objvar TSRMLS_CC));  
}

访问属性

你已经看到了, 类方法可以通过getThis()获取到当前对象实例. 将这个宏的结果或其它包含对象实例的zval *与Z_OBJPROP_P()宏组合, 得到的HashTable *就包含了该对象的所有属性.

对象的属性列表是一个包含zval *的HashTable *, 它只是另外一种放在特殊位置的用户空间变量列表. 和使用zend_hash_find(EG(active_symbol_table), ...)从当前作用域获取变量一样, 你也可以使用第8章"在数组和HashTable上工作"中学习的zend_hash-API去获取或设置对象的属性.

例如, 假设在变量rcvdclass这个zval *中包含的是Sample2_FirstClass的实例, 下面的代码块就可以从它的标准属性HashTable中取到属性foo.

zval **fooval;  
if (zend_hash_find(Z_OBJPROP_P(rcvdclass),  
        "foo", sizeof("foo"), (void**)&fooval) == FAILURE) {  
    /* $rcvdclass->foo doesn&#39;t exist */  
    return;  
}

要向属性表中增加元素, 则是这个过程的逆向过程, 调用zend_hash_add()去增加元素, 或者也可以将第8章介绍数组时介绍的add_assoc_*()族函数的assoc替换为property来处理对象.

下面的构造器函数为Sample2_FirstClass的实例提供了一些预先设置的默认属性:

PHP_NAMED_FUNCTION(php_sample2_fc_ctor)  
{  
    /* 为了简洁, 同时演示函数名可以是任意的, 这里实现的函数名并不是类名 */  
    zval *objvar = getThis();  
  
    if (!objvar) {  
        php_error_docref(NULL TSRMLS_CC, E_WARNING,  
                        "Constructor called statically!");  
        RETURN_FALSE;  
    }  
  
    add_property_long(objvar, "life", 42);  
    add_property_double(objvar, "pi", 3.1415926535);  
    /* 构造器的返回值会被忽略(请回顾前面构造器的例子) */  
}

现在可以通过php_sample2_firstclass_functions列表将它连接到对象的构造器:

PHP_NAMED_FE(sample2_firstclass, php_sample2_fc_ctor, NULL)

译注: 由于前面的sample_new()工厂函数在call_user_function_ex()调用构造器时使用的是静态方法的调用格式, 因此, 如果是使用这个工厂函数触发的构造器调用, getThis()就不会有期望的结果. 因此译者对例子进行了相应的修改, 读者如果在这块遇到问题可以参考译者的代码.

PHP_FUNCTION(sample_new)  
{  
    int                 argc    = ZEND_NUM_ARGS();  
    zval                ***argv = safe_emalloc(sizeof(zval **), argc, 0);   
    zend_class_entry    **ce;       /* 译注: 这里在译者的环境(php-5.4.9)是二级间访 */  
  
    /* 数组方式读取所有传入参数 */  
    if ( argc == 0 ||    
            zend_get_parameters_array_ex(argc, argv) == FAILURE ) {   
        efree(argv);  
        WRONG_PARAM_COUNT;  
    }     
  
    /* 隔离第一个参数(隔离为了使下面的类型转换不影响原始数据) */  
    SEPARATE_ZVAL(argv[0]);  
    /* 将第一个参数转换为字符串类型, 并转为小写(因为php的类名是不区分大小写的) */  
    convert_to_string(*argv[0]);  
    php_strtolower(Z_STRVAL_PP(argv[0]), Z_STRLEN_PP(argv[0]));  
    /* 在类的HashTable中查找提供的类是否存在, 如果存在, ce中就得到了对应的zend_class_entry * */  
    if ( zend_hash_find(EG(class_table), Z_STRVAL_PP(argv[0]), Z_STRLEN_PP(argv[0]) + 1, (void **)&ce) == FAILURE ) {   
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Class %s does not exist.", Z_STRVAL_PP(argv[0]));  
        zval_ptr_dtor(argv[0]);  
        efree(argv);  
        RETURN_FALSE;  
    }     
  
    /* 将返回值初始化为查找到的类的对象 */  
    object_init_ex(return_value, *ce);  
    /* 检查类是否有构造器 */  
    if ( zend_hash_exists(&(*ce)->function_table, Z_STRVAL_PP(argv[0]), Z_STRLEN_PP(argv[0]) + 1) ) {   
#define DYNAMIC_CONSTRUCTOR  
#ifndef DYNAMIC_CONSTRUCTOR  
        zval    *ctor;  
#endif  
        zval    *dummy = NULL;  
  
#ifndef DYNAMIC_CONSTRUCTOR  
        /* 将ctor构造为一个数组, 对应的用户空间形式为: array(argv[0], argv[0]),  
         * 实际上对应于用户空间调用类的静态方法时$funcname的参数形式: 
         * array(类名, 方法名) 
         */  
        MAKE_STD_ZVAL(ctor);  
        array_init(ctor);  
        zval_add_ref(argv[0]);  
        add_next_index_zval(ctor, *argv[0]);  
        zval_add_ref(argv[0]);  
        add_next_index_zval(ctor, *argv[0]);  
#endif  
        /* 调用函数 */  
        if ( call_user_function_ex(&(*ce)->function_table,  
#ifndef DYNAMIC_CONSTRUCTOR  
                NULL, ctor,  
#else  
                &return_value, *argv[0],  
#endif  
                &dummy, argc - 1, argv + 1, 0, NULL TSRMLS_CC) == FAILURE ) {  
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call constructor");  
        }  
        /* 如果有返回值直接析构丢弃 */  
        if ( dummy ) {  
            zval_ptr_dtor(&dummy);  
        }  
#ifndef DYNAMIC_CONSTRUCTOR  
        /* 析构掉临时使用(用来描述所调用方法名)的数组 */  
        zval_ptr_dtor(&ctor);  
#endif  
    }  
    /* 析构临时隔离出来的第一个参数(类名) */  
    zval_ptr_dtor(argv[0]);  
    /* 释放实参列表空间 */  
    efree(argv);  
}

译注: 现在, 就可以用函数中是否定义DYNAMIC_CONSTRUCTOR这个宏来切换构造器的调用方式, 以方便读者理解.

小结

尽管ZE1/php4提供的类功能最好少用, 但是由于当前php4在产品环境下还是广泛使用的, 因此做这个兼容还是有好处的. 本章涉及的技术可以让你灵活的编写各种功能的代码, 它们现在可以编译运行, 并且未来也将继续可以工作.

下一章, 你将看到php5中真正的面向对象, 如果你想要OOP, 从中你就可以得到升级的理由, 并且, 升级后你肯定再也不愿回头.

以上就是 [翻译][php扩展开发和嵌入式]第10章-php4的对象的内容,更多相关内容请关注PHP中文网(www.php.cn)!


Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
The Continued Use of PHP: Reasons for Its EnduranceThe Continued Use of PHP: Reasons for Its EnduranceApr 19, 2025 am 12:23 AM

What’s still popular is the ease of use, flexibility and a strong ecosystem. 1) Ease of use and simple syntax make it the first choice for beginners. 2) Closely integrated with web development, excellent interaction with HTTP requests and database. 3) The huge ecosystem provides a wealth of tools and libraries. 4) Active community and open source nature adapts them to new needs and technology trends.

PHP and Python: Exploring Their Similarities and DifferencesPHP and Python: Exploring Their Similarities and DifferencesApr 19, 2025 am 12:21 AM

PHP and Python are both high-level programming languages ​​that are widely used in web development, data processing and automation tasks. 1.PHP is often used to build dynamic websites and content management systems, while Python is often used to build web frameworks and data science. 2.PHP uses echo to output content, Python uses print. 3. Both support object-oriented programming, but the syntax and keywords are different. 4. PHP supports weak type conversion, while Python is more stringent. 5. PHP performance optimization includes using OPcache and asynchronous programming, while Python uses cProfile and asynchronous programming.

PHP and Python: Different Paradigms ExplainedPHP and Python: Different Paradigms ExplainedApr 18, 2025 am 12:26 AM

PHP is mainly procedural programming, but also supports object-oriented programming (OOP); Python supports a variety of paradigms, including OOP, functional and procedural programming. PHP is suitable for web development, and Python is suitable for a variety of applications such as data analysis and machine learning.

PHP and Python: A Deep Dive into Their HistoryPHP and Python: A Deep Dive into Their HistoryApr 18, 2025 am 12:25 AM

PHP originated in 1994 and was developed by RasmusLerdorf. It was originally used to track website visitors and gradually evolved into a server-side scripting language and was widely used in web development. Python was developed by Guidovan Rossum in the late 1980s and was first released in 1991. It emphasizes code readability and simplicity, and is suitable for scientific computing, data analysis and other fields.

Choosing Between PHP and Python: A GuideChoosing Between PHP and Python: A GuideApr 18, 2025 am 12:24 AM

PHP is suitable for web development and rapid prototyping, and Python is suitable for data science and machine learning. 1.PHP is used for dynamic web development, with simple syntax and suitable for rapid development. 2. Python has concise syntax, is suitable for multiple fields, and has a strong library ecosystem.

PHP and Frameworks: Modernizing the LanguagePHP and Frameworks: Modernizing the LanguageApr 18, 2025 am 12:14 AM

PHP remains important in the modernization process because it supports a large number of websites and applications and adapts to development needs through frameworks. 1.PHP7 improves performance and introduces new features. 2. Modern frameworks such as Laravel, Symfony and CodeIgniter simplify development and improve code quality. 3. Performance optimization and best practices further improve application efficiency.

PHP's Impact: Web Development and BeyondPHP's Impact: Web Development and BeyondApr 18, 2025 am 12:10 AM

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

How does PHP type hinting work, including scalar types, return types, union types, and nullable types?How does PHP type hinting work, including scalar types, return types, union types, and nullable types?Apr 17, 2025 am 12:25 AM

PHP type prompts to improve code quality and readability. 1) Scalar type tips: Since PHP7.0, basic data types are allowed to be specified in function parameters, such as int, float, etc. 2) Return type prompt: Ensure the consistency of the function return value type. 3) Union type prompt: Since PHP8.0, multiple types are allowed to be specified in function parameters or return values. 4) Nullable type prompt: Allows to include null values ​​and handle functions that may return null values.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

SublimeText3 English version

SublimeText3 English version

Recommended: Win version, supports code prompts!

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

Atom editor mac version download

Atom editor mac version download

The most popular open source editor