分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 技术分享

PHP-CPP开发扩展(五)

发布时间:2023-09-06 02:07责任编辑:蔡小小关键词:PHP

PHP-CPP是一个用于开发PHP扩展的C++库。本节讲解如何在C++中实现PHP类。

类和对象

类和对象

怎样在PHP-CPP里写出PHP的类呢?很简单,看下面的例子:
main.cpp

/** * User: 公众号: 飞鸿影的博客(fhyblog) * Date: 2018/7 */#include <time.h>#include <phpcpp.h>/** * ?Counter class that can be used for counting */class Counter : public Php::Base{private: ???/** ????* ?The initial value ????* ?@var ???int ????*/ ???int _value = 0;public: ???/** ????* ?C++ constructor and destructor ????*/ ???Counter() = default; ???virtual ~Counter() = default; ???/** ????* ?Update methods to increment or decrement the counter ????* ?Both methods return the NEW value of the counter ????* ?@return int ????*/ ???Php::Value increment() { return ++_value; } ???Php::Value decrement() { return --_value; } ???/** ????* ?Method to retrieve the current counter value ????* ?@return int ????*/ ???Php::Value value() const { return _value; } ???????//类的静态成员函数 ???static Php::Value gettime() {return time(NULL);}};/** * ?Switch to C context to ensure that the get_module() function * ?is callable by C programs (which the Zend engine is) */extern "C" { ???/** ????* ?Startup function that is called by the Zend engine ?????* ?to retrieve all information about the extension ????* ?@return void* ????*/ ???PHPCPP_EXPORT void *get_module() { ???????????// 必须是static类型,因为扩展对象需要在PHP进程内常驻内存 ???????static Php::Extension extension("helloworld", "1.0.0"); ???????????????//初始化导出类 ???????Php::Class<Counter> counter("Counter"); ???????????????//注册导出类的可访问普通函数 ???????counter.method<&Counter::increment> ("increment"); ???????counter.method<&Counter::decrement> ("decrement"); ???????counter.method<&Counter::value> ("value"); ???????????????//注册导出类的可访问静态函数 ???????counter.method<&Counter::gettime>("gettime"); ???????//注册导出类,使用右值引用方式,优化资源使用 ???????extension.add(std::move(counter)); ???????????????// 返回扩展对象指针 ???????return extension; ???}}

首先,C++类必须继承自Php::Base;其次,当我们将类添加到扩展对象时,还必须指定要从PHP访问的所有方法;最后再注册导出类。

我们先测试:

/** * User: 公众号: 飞鸿影的博客(fhyblog) * Date: 2018/7 */$counter = new Counter;echo 'result of increment() = '. $counter->increment() . PHP_EOL;echo 'result of increment() = '. $counter->increment() . PHP_EOL;echo 'result of decrement() = '. $counter->decrement() . PHP_EOL;echo 'result of value() = '. $counter->value() . PHP_EOL;echo 'result of gettime() = '. Counter::gettime() . PHP_EOL;

输出:

result of increment() = 1result of increment() = 2result of decrement() = 1result of value() = 1result of gettime() = 1531621728

访问修饰符

我们还可以对导出的方法添加访问修饰符:

//初始化导出类Php::Class<Counter> counter("Counter");//注册导出类的可访问普通函数counter.method<&Counter::increment> ("increment", Php::Private, { ???Php::ByVal("a", Php::Type::Numeric)});counter.method<&Counter::decrement> ("decrement", Php::Protected, { ???Php::ByVal("a", Php::Type::Numeric)});counter.method<&Counter::value> ("value");

Php::Class::method第二个参数支持设置访问修饰符,默认是public;第三个参数和普通函数一样,支持设置参数类型。

支持的访问修饰符:

extern PHPCPP_EXPORT const int Static;extern PHPCPP_EXPORT const int Abstract;extern PHPCPP_EXPORT const int Final;extern PHPCPP_EXPORT const int Public;extern PHPCPP_EXPORT const int Protected;extern PHPCPP_EXPORT const int Private;extern PHPCPP_EXPORT const int Const;

有一点需要注意:C++里要导出的方法,必须全是Public的, 即使我们在PHP中将它们标记为私有或受保护。因为我们写的方法由PHP-CPP库调用,如果将它们设为私有,它们将对库不可见。

抽象类、Final类

声明类为Final很简单,只需要在初始化导出类的时候声明一下即可:

Php::Class<Counter> counter("Counter", Php::Final);

那么怎么声明一个抽象类呢?上面的例子里Php::Class::method都传入了真正的C ++方法的地址,但是抽象方法通常没有实现,那么我们需要怎么提供指向方法的指针?幸运的是,在PHP-CPP里注册抽象方法不用提供指向C ++方法的指针。

示例:
抽象类原申明:

/** * User: 公众号: 飞鸿影的博客(fhyblog) * Date: 2018/7 */#include <phpcpp.h>//类声明class MyAbstract : public Php::Base{};extern "C" { ???????PHPCPP_EXPORT void *get_module() ????{ ???????// 必须是static类型,因为扩展对象需要在PHP进程内常驻内存 ???????static Php::Extension extension("helloworld", "1.0.0"); ???????????????//初始化导出类 ???????Php::Class<MyAbstract> my_abstract("MyAbstract", Php::Abstract); ???????????????//注册抽象方法:如果不给出C++方法的地址,该方法自动变成抽象方法 ???????my_abstract.method("myAbstractMethod", { ????????????Php::ByVal("a", Php::Type::String, true) ????????}); ???????????????extension.add(std::move(my_abstract)); ???????????????// 返回扩展对象指针 ???????return extension; ???}}

我们在test.php尝试去实例化MyAbstract类,提示:

PHP Fatal error: ?Uncaught Error: Cannot instantiate abstract class MyAbstract

注:官方示例里初始化导出类里没有加Php::Abstract,测试的时候发现还是可以实例化的,只是调用抽象方法才报错。

构造函数和析构函数

在C++代码里,PHP的构造函数和析构函数本质上是普通方法。明白了这点,就不难实现了。

示例:

/** * User: 公众号: 飞鸿影的博客(fhyblog) * Date: 2018/7 */#include <phpcpp.h>/** * ?Simple counter class */class Counter : public Php::Base{private: ???/** ????* ?Internal value ????* ?@var int ????*/ ???int _value = 0;public: ???/** ????* ?c++ constructor ????*/ ???Counter() = default; ???/** ????* ?c++ destructor ????*/ ???virtual ~Counter() = default; ???/** ????* ?php "constructor" ????* ?@param ?params ????*/ ???void __construct(Php::Parameters &params) ???{ ???????// copy first parameter (if available) ???????if (!params.empty()) _value = params[0]; ???} ???/** ????* ?functions to increment and decrement ????*/ ???Php::Value increment() { return ++_value; } ???Php::Value decrement() { return --_value; } ???Php::Value value() const { return _value; }};/** * ?Switch to C context so that the get_module() function can be * ?called by C programs (which the Zend engine is) */extern "C" { ???/** ????* ?Startup function for the extension ????* ?@return void* ????*/ ???PHPCPP_EXPORT void *get_module() { ???????static Php::Extension myExtension("my_extension", "1.0"); ???????// description of the class so that PHP knows which methods are accessible ???????Php::Class<Counter> counter("Counter"); ???????counter.method<&Counter::__construct>("__construct"); ???????counter.method<&Counter::increment>("increment"); ???????counter.method<&Counter::decrement>("decrement"); ???????counter.method<&Counter::value>("value"); ???????// add the class to the extension ???????myExtension.add(std::move(counter)); ???????// return the extension ???????return myExtension; ???}}

如果需要构造函数为私有的,只需要在注册的时候加个flag:

counter.method<&Counter::__construct>("__construct", Php::Private);

如果要禁止被clone,可以:

// alternative way to make an object unclonablecounter.method("__clone", Php::Private);

接口

接口(Interface)由于不需要具体方法的实现,我们可以通过与定义类的方式类似的方式来实现。唯一的区别是我们不使用Php::Class<YourClass>,而是一个Php::Interface实例。

//初始化Php::Interface interface("MyInterface");//添加成员方法interface.method("myMethod", { ????Php::ByVal("value", Php::Type::String, true) });//注册到扩展extension.add(std::move(interface));

继承

implement 实现

我们除了可以在PHP代码去实现接口或者继承类,也可以在C++里实现。该Php::Class<YourClass>对象有extends()implements(),可用于指定基类和实现的接口。我们需要传入之前配置的类或接口。我们来看一个例子。

/** * User: 公众号: 飞鸿影的博客(fhyblog) * Date: 2018/7 */#include <phpcpp.h>#include <iostream>class MyClass : public Php::Base{ ???public: ???????Php::Value myMethod(Php::Parameters &params){ ???????????Php::out << "MyClass" << std::endl; ???????????return params; ???????}};extern "C" { ???????PHPCPP_EXPORT void *get_module() ????{ ???????static Php::Extension extension("helloworld", "1.0.0"); ???????????????//定义接口 ???????Php::Interface interface("MyInterface"); ???????interface.method("myMethod", { ????????????Php::ByVal("value", Php::Type::String, true) ????????}); ???????extension.add(std::move(interface)); ???????// 注册一个自定义类 ???????Php::Class<MyClass> myClass("MyClass"); ???????// 实现接口定义 ???????myClass.implements(interface); ???????myClass.method<&MyClass::myMethod>("myMethod", { ???????????Php::ByVal("value", Php::Type::String, true) ????????}); ???????extension.add(std::move(myClass)); ???????????????// 返回扩展对象指针 ???????return extension; ???}}

测试:

$obj = new MyClass();var_dump($obj->myMethod(11));

extends 继承

PHP的继承与C++的继承没有直接关系,必须显示使用Php::Class::extends()进行继承。

还是接着上面的例子说明。

/** * User: 公众号: 飞鸿影的博客(fhyblog) * Date: 2018/7 */#include <phpcpp.h>#include <iostream>class MyClass : public Php::Base{ ???public: ???????Php::Value myMethod(Php::Parameters &params){ ???????????Php::out << "MyClass" << std::endl; ???????????return params; ???????}};class MySubClass : public Php::Base{};extern "C" { ???????PHPCPP_EXPORT void *get_module() ????{ ???????static Php::Extension extension("helloworld", "1.0.0"); ???????????????//定义接口 ???????Php::Interface interface("MyInterface"); ???????interface.method("myMethod", { ????????????Php::ByVal("value", Php::Type::String, true) ????????}); ???????????????// 注册一个自定义类 ???????Php::Class<MyClass> myClass("MyClass"); ???????// 实现接口定义 ???????myClass.implements(interface); ???????myClass.method<&MyClass::myMethod>("myMethod", { ???????????Php::ByVal("value", Php::Type::String, true) ????????}); ???????????????Php::Class<MySubClass> mySubClass("MySubClass"); ???????mySubClass.extends(myClass); ???????????????extension.add(std::move(interface)); ???????extension.add(std::move(mySubClass)); ???????extension.add(std::move(myClass)); ???????????????// 返回扩展对象指针 ???????return extension; ???}}

注:注册类(extension.add)需要放到extends方法的后面,也就是不能先注册父类再使用extends,否则无法继承。建议实际编程的时候注册统一放到最后面。

魔术方法

在PHP-CPP里,仅__construct()需要显示的在get_module()里注册,其他的魔术方法像__get()__set()__call()等都不需要注册。

/** * User: 公众号: 飞鸿影的博客(fhyblog) * Date: 2018/7 */#include <phpcpp.h>/** * ?A sample class, that has some pseudo properties that map to native types */class User : public Php::Base{private: ???/** ????* ?Name of the user ????* ?@var ???std::string ????*/ ???std::string _name; ???/** ????* ?Email address of the user ????* ?@var ???std::string ????*/ ???std::string _email;public: ???/** ????* ?C++ constructor and C++ destructpr ????*/ ???User() = default; ???virtual ~User() = default; ???/** ????* ?Get access to a property ????* ?@param ?name ???????Name of the property ????* ?@return Value ??????Property value ????*/ ???Php::Value __get(const Php::Value &name) ???{ ???????// check if the property name is supported ???????if (name == "name") return _name; ???????if (name == "email") return _email; ???????// property not supported, fall back on default ???????return Php::Base::__get(name); ???} ???/** ????* ?Overwrite a property ????* ?@param ?name ???????Name of the property ????* ?@param ?value ??????New property value ????*/ ???void __set(const Php::Value &name, const Php::Value &value) ????{ ???????// check the property name ???????if (name == "name") ????????{ ???????????// store member ???????????_name = value.stringValue(); ???????} ???????// we check emails for validity ???????else if (name == "email") ???????{ ???????????// store the email in a string ???????????std::string email = value; ???????????// must have a '@' character in it ???????????if (email.find('@') == std::string::npos) ????????????{ ???????????????// email address is invalid, throw exception ???????????????throw Php::Exception("Invalid email address"); ???????????} ???????????// store the member ???????????_email = email; ???????} ???????// other properties fall back to default ???????else ???????{ ???????????// call default ???????????Php::Base::__set(name, value); ???????} ???} ???/** ????* ?Check if a property is set ????* ?@param ?name ???????Name of the property ????* ?@return bool ????*/ ???bool __isset(const Php::Value &name) ????{ ???????// true for name and email address ???????if (name == "name" || name == "email") return true; ???????// fallback to default ???????return Php::Base::__isset(name); ???} ???/** ????* ?Remove a property ????* ?@param ?name ???????Name of the property to remove ????*/ ???void __unset(const Php::Value &name) ???{ ???????// name and email can not be unset ???????if (name == "name" || name == "email") ????????{ ???????????// warn the user with an exception that this is impossible ???????????throw Php::Exception("Name and email address can not be removed"); ???????} ???????// fallback to default ???????Php::Base::__unset(name); ???}};/** * ?Switch to C context to ensure that the get_module() function * ?is callable by C programs (which the Zend engine is) */extern "C" { ???/** ????* ?Startup function that is called by the Zend engine ?????* ?to retrieve all information about the extension ????* ?@return void* ????*/ ???PHPCPP_EXPORT void *get_module() { ???????// extension object ???????static Php::Extension myExtension("my_extension", "1.0"); ???????// description of the class so that PHP knows ????????// which methods are accessible ???????Php::Class<User> user("User"); ???????// add the class to the extension ???????myExtension.add(std::move(user)); ???????// return the extension ???????return myExtension; ???}}

测试:

<?php/** * User: 公众号: 飞鸿影的博客(fhyblog) * Date: 2018/7 */// initialize user and set its name and email address$user = new User();$user->name = "John Doe";$user->email = "john.doe@example.com";// show the email addressecho($user->email."\n");// remove the email address (this will cause an exception)unset($user->email);?>

(未完待续)

想第一时间获取最新动态,欢迎关注关注飞鸿影的博客(fhyblog),不定期为您呈现技术干货。

PHP-CPP开发扩展(五)

原文地址:https://www.cnblogs.com/52fhy/p/9388764.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved