cpp 面向对象小题目_用PHP-CPP开发PHP扩展:面向对象的代码

cpp 面向对象小题目

In my Part 1 on building a PHP extension with PHP-CPP, we have seen some basics in using PHP-CPP to create our first skeleton PHP extension and covered some important terminologies.

关于使用PHP-CPP构建PHP扩展的第1部分中 ,我们了解了使用PHP-CPP创建我们的第一个框架PHP扩展的一些基础知识,并介绍了一些重要的术语。

In this part, we further elaborate its OO features. We will mimic a complex number (in the form of 3+4i) class to demonstrate some more useful and powerful sides of the PHP-CPP library.

在这一部分中,我们进一步阐述其面向对象的功能。 我们将模拟一个复数(以3+4i的形式)类,以演示PHP-CPP库的一些更有用和更强大的方面。

We start by modifying the empty project files provided by PHP-CPP and change the following two files to suit our new library (complex.so in this case) and my system :

我们首先修改PHP-CPP提供的空项目文件 ,然后更改以下两个文件以适合我们的新库(在这种情况下为complex.so )和我的系统:

  • Rename yourtextension.ini to complex.ini and change its content to extension=complex.so.

    yourtextension.ini重命名为complex.ini ,并将其内容更改为extension=complex.so

  • Modify a few lines in Makefile:

    修改Makefile的几行:

NAME                =   complex
INI_DIR             =   /etc/php5/cli/conf.d

Now we move on to create our Complex class in main.cpp.

现在我们继续在main.cpp创建Complex类。

C ++构造函数和PHP构造函数 (C++ constructor and PHP constructor)

In a C++ class, there are constructors and destructors. Constructors appear in a familiar form with no return type and the class name as its function name, with optional different sets of parameters (in their overloaded versions), while destructors have no return type, no parameters, share the class name prefixed with a tilt (~):

在C ++类中,有构造函数和析构函数。 构造函数以熟悉的形式出现,没有返回类型,而类名作为其函数名称,带有可选的不同参数集(在其重载版本中),而析构函数没有返回类型,没有参数,共享以斜线为前缀的类名( ~ ):

class Complex
{
    Complex();
    // We can have many other overloaded versions of the constructor 
    ~Complex();
}

We also know that in PHP, we have some “magic” methods, in particular, __construct() and __destruct() as the class constructor and destructor.

我们也知道在PHP中,我们有一些“魔术”方法,特别是__construct()__destruct()作为类的构造函数和析构函数。

PHP-CPP supports this kind of PHP-like magic method for constructors/destructors. This makes our implementation of a PHP extension with class easier.

PHP-CPP支持这种构造函数/析构函数类似PHP的魔术方法。 这使我们更容易实现带有类PHP扩展。

(The PHP-CPP official documentation provides detailed explanations on the difference between these two “constructors/destructors”. Please read that and other related documents for more details.)

( PHP-CPP官方文档提供了关于这两个“构造函数/析构函数”之间区别的详细说明。请阅读该文档以及其他相关文档以获取更多详细信息。)

My personal view is that, as we will eventually use the class (written in C++) within the PHP script, we should implement both: C++ constructors/destructors and PHP-like magic constructors/destructors in our class. The code snippet is shown below:

我个人的观点是,由于我们最终将在PHP脚本中使用该类(用C ++编写),因此我们应该同时实现:类中的C ++构造函数/析构函数和类似PHP的魔术构造函数/析构函数。 该代码段如下所示:

class Complex : public Php::Base {
private:
    double r = 0, i = 0;

public:
    /**
     *  C++ constructor and destructor
     */
    Complex() {
    }

    virtual ~Complex() {
    }

    Php::Value getReal() {
        return r;
    }

    Php::Value getImage() {
        return i;
    }

    void __construct(Php::Parameters &params) {
        if (params.size() == 2) {
            r = params[0];
            i = params[1];
        } else {
            r=0;
            i=0;
        }
    }

In this code segment, a few things need further elaboration:

在此代码段中,需要做一些进一步的说明:

  1. Any class that is declared in our library MUST inherit from Php::Base. This is a requirement by PHP-CPP. Php::Base has some fundamental implementations of a few low-level methods for object-oriented operation. (The header file for Php::Base class is base.h.)

    在我们的库中声明的任何类都必须继承自Php::Base 。 这是PHP-CPP的要求。 Php::Base具有一些面向对象操作的一些底层方法的一些基本实现。 ( Php::Base类的头文件是base.h )

  2. We declared both a C++ constructor/destructor and a PHP-like magic constructor. The latter is also parameterized so that we can set the real/image part of a complex number by parameters passed in from PHP during the object instantiation.

    我们同时声明了C ++构造函数/析构函数和类似PHP的魔术构造函数。 后者也经过参数化,因此我们可以通过对象实例化期间从PHP传入的参数来设置复数的实数/图像部分。
  3. As the real/image part of a complex number defined in our class is private, we also defined two getter functions to return these two parts: getReal(), getImage(). PHP-CPP also supports properties in class. Please refer to this document for more details.

    由于在我们的类中定义的复数的实/图像部分是private ,因此我们还定义了两个getter函数以返回这两个部分: getReal()getImage() 。 PHP-CPP还支持类中的属性。 有关更多详细信息,请参阅此文档

  4. Finally, as this is a fairly simple class, we do not really add in any code in the C++ constructor/destructors. All initialization work is done in the PHP-like constructor.

    最后,由于这是一个非常简单的类,因此我们实际上并未在C ++构造函数/析构函数中添加任何代码。 所有初始化工作都是在类似PHP的构造函数中完成的。

成员函数返回复数的mod (A member function that returns the mod of a complex number)

A mod of a complex number is defined as the distance to the original point in a Descartes coordinate system. It is calculated by the below formula:

复数的模数定义为到笛卡尔坐标系中到原始点的距离。 通过以下公式计算得出:

mod=sqrt(r*r+i*i)

This function is being discussed first as it is very simple: it only uses the class members for processing and returns a scalar value.

首先讨论此函数,因为它非常简单:它仅使用类成员进行处理并返回标量值。

The implementation of this function is thus straightforward.

因此,该功能的实现非常简单。

Php::Value mod() const {
    return (double)sqrt(r * r + i * i);
}

You may need to #include <cmath> for the math operations.

您可能需要#include <cmath>进行数学运算。

We will address how to register this function so that it is available to PHP later.

我们将介绍如何注册此功能,以便以后可用于PHP。

Like the regular function signatures we discussed in Part 1, PHP-CPP only supports 8 signatures for a member function:

就像我们在第1部分中讨论的常规函数​​签名一样,PHP-CPP仅支持8个成员函数签名:

// signatures of supported regular methods
void        YourClass::example1();
void        YourClass::example2(Php::Parameters &params);
Php::Value  YourClass::example3();
Php::Value  YourClass::example4(Php::Parameters &params);
void        YourClass::example5() const;
void        YourClass::example6(Php::Parameters &params) const;
Php::Value  YourClass::example7() const;
Php::Value  YourClass::example8(Php::Parameters &params) const;

Any function with a different signature than the above can still appear in the class declaration but will NOT be able to be registered and will NOT be visible to PHP script.

具有与上述签名不同的签名的任何函数仍可以出现在类声明中,但将无法注册,并且对PHP脚本不可见。

In this mod() function, we are using its 7th form.

在此mod()函数中,我们使用其第七种形式。

成员函数做加法 (A member function doing addition)

Creating a function doing addition of two complex numbers is a bit trickier.

创建一个将两个复数相加的函数比较棘手。

In traditional C++, we have 3 options:

在传统的C ++中,我们有3个选项:

  1. Override the operator + so that the addition operation on two numbers is as simple and elegant as: c+d. Unfortunately, this is not possible in PHP as PHP does not support operator overriding.

    重写运算符+以便对两个数字进行加法运算就像c+d一样简单而优雅。 不幸的是,这在PHP中是不可能的,因为PHP不支持运算符覆盖。

  2. A member function of this class called “add“, with another complex number as the parameter. So the addition will be done like this: c->add(d).

    该类的成员函数称为“ add ”,其中另一个复数作为参数。 因此加法将像这样完成: c->add(d)

  3. A regular function with two parameters and returns a new complex, like this: complex_add(c, d).

    具有两个参数的常规函数​​并返回一个新的复数,例如: complex_add(c, d)

Option 3 is generally considered to be the worst option and we will see how to create such an addition function using option 2.

通常认为选项3是最差的选项,我们将看到如何使用选项2创建这样的加法函数。

Php::Value add(Php::Parameters &params)
    {
        Php::Value t=params[0];
        Complex *a=(Complex *)t.implementation();

        r+=(double)a->getReal();
        i+=(double)a->getImage();

        return this;
    }``

The add function itself has two aspects of critical importance:

add函数本身具有两个至关重要的方面:

Firstly, please note the function signature. It uses the 4th form supported by PHP-CPP. It returns a Php::Value and accepts a parameter of type Php::Parameters, where all the parameters – in this case, there shall only be one – are passed in an array form.

首先,请注意功能签名。 它使用PHP-CPP支持的第四种形式。 它返回一个Php::Value并接受类型为Php::Parameters ,其中所有参数(在这种情况下,只有一个)将以数组形式传递。

Then the first line assigns the first parameter that is passed into the function (params[0]) to a Php::Value type variable t.

然后,第一行将传递到函数中的第一个参数( params[0] )分配给Php::Value类型变量t

As we will see later in the function registration, we can be pretty sure that this variable, though assigned to Php::Value type, is actually a Complex type variable. Thus, we can safely cast that variable to a pointer to a Complex class instance. This is exactly what the 2nd line does:

正如我们将在函数注册的后面部分看到的那样,我们可以很确定地将此变量(尽管分配给Php::Value类型)实际上是Complex类型变量。 因此,我们可以安全地将该变量转换为指向Complex类实例的指针。 这正是第二行所做的:

Complex *a=(Complex *)t.implementation();

The implementation() method is implemented in the Php::Value class in value.h. According to the explanation of that function, which I quote below:

implementation()方法在value.hPhp::Value类中value.h 。 根据对该功能的解释,我在下面引用:

/**
     *  Retrieve the original implementation
     * 
     *  This only works for classes that were implemented using PHP-CPP,
     *  it returns nullptr for all other classes
     * 
     *  @return Base*
     */

it does the critical task of casting a Php::Value into its underlying class implementation.

它完成了将Php::Value转换为其基础类实现的关键任务。

This also explains why we have to derive our own classes from Php::Base as this function returns a Php::Base pointer.

这也解释了为什么我们必须从Php::Base派生我们自己的类,因为此函数返回Php::Base指针。

Ironically, such an important function is not explained in PHP-CPP’s current document set. I got this tip from one of the authors of PHP-CPP (Emiel, thanks!) through some email exchange.

具有讽刺意味的是,PHP-CPP的当前文档集中没有解释这种重要功能。 我是通过PHP-CPP的一位作者(通过Emiel,谢谢!)通过电子邮件交换获得的。

When this implementation is in place, the add function is possible.

implementationimplementation后,可以使用add功能。

魔术功能,以更友好的方式显示复数 (A magic function to display a complex number in a more friendly way)

PHP-CPP supports PHP “magic methods”. We have seen __construct() in previous paragraphs and let’s further demonstrate this by creating a __toString() method in our Complex class to print the complex number in a more intuitive way, like 3+4i. (You may need to #include <sstream> for string output manipulations in the below code.)

PHP-CPP支持PHP “魔术方法” 。 我们已经在前面的段落中看到了__construct() ,并且通过在Complex类中创建__toString()方法来以更直观的方式(例如3+4i打印复数来进一步说明这一点。 (您可能需要在以下代码中#include <sstream>进行字符串输出操作。)

Php::Value __toString()
    {
        std::ostringstream os;

        os<<r;
        if(i>=0)
            os<<'+';

        os<<i<<'i';

        return os.str();
    }

The implementation of this function is straightforward.

此功能的实现很简单。

注册到目前为止创建的所有功能 (Registration of all the functions created so far)

For this version of the mimicked Complex class, I have only implemented the above few functions. Interested users are encouraged to expand this class to add in more functionality (basic arithmetic operations, for example). The code for the Complex class and the demo in Part 1 can be cloned from Github.

对于这个模拟的Complex类版本,我仅实现了上述几个功能。 鼓励感兴趣的用户扩展此类以添加更多功能(例如,基本算术运算)。 可以从Github中克隆用于Complex类的代码和第1部分中的演示。

To make these functions visible (callable) from a PHP script, we need to register them. Registering a class and its methods is a bit different from registering a regular function:

为了使这些函数在PHP脚本中可见(可调用),我们需要注册它们。 注册类及其方法与注册常规函数有点不同:

extern "C" {

    PHPCPP_EXPORT void *get_module() {
        // create static instance of the extension object
        static Php::Extension myExtension("complex", "1.0");

        // description of the class so that PHP knows which methods are accessible
        Php::Class<Complex> complex("Complex");

        // register the methods, and specify the parameters
        complex.method("mod", &Complex::mod, {});
        complex.method("__construct", &Complex::__construct);
        complex.method("add", &Complex::add, {
            Php::ByVal("op", "Complex", false, true)
        });

        // add the class to the extension
        myExtension.add(std::move(complex));

        // return the extension
        return myExtension;
    }
}

In this get_module() function, we created a Php::Class variable (complex) to hold our class (Complex) information. Then we register the member functions with complex.method().

在此get_module()函数中,我们创建了一个Php::Class变量( complex )来保存我们的类( Complex )信息。 然后,我们使用complex.method()注册成员函数。

In the last complex.method() to register the add function, we specified its parameter number and type. To find out more on how to register class and declare method parameters, please refer to Parameters and Classes and objects.

在最后一个注册add函数的complex.method()中,我们指定了其参数编号和类型。 要了解有关如何注册类和声明方法参数的更多信息,请参阅ParametersClasses和objects

Finally, we moved the complex variable into the extension and returned that extension.

最后,我们将complex变量移入扩展名并返回该扩展名。

编译,安装和测试 (Compile, Install and Test)

Now, we can compile and install this complex.so extension with the following command:

现在,我们可以使用以下命令编译并安装这个complex.so扩展:

make && sudo make install

If everything goes smoothly, the extension will be installed and ready to use.

如果一切顺利,扩展程序将被安装并可以使用。

To test the extension, let’s write a few lines of PHP code:

为了测试扩展,让我们写几行PHP代码:

<?php

$c=new Complex(-3,-4);
echo $c->mod()."\n"; // First echo

$d=new Complex(4,3);

echo $c->add($d)->mod()."\n"; // Second echo

echo ((string)$d."\n"); // Third echo

$f=new \DateTime();
$g=$d->add($f); // Fourth echo but displays an error

The first echo will print 5, exactly what we expected.

第一个echo将打印5 ,恰好是我们期望的。

The second echo will display 1.41421.... As we have returned a this pointer from add function, we can chain the addition operation and the mod() in one line.

第二个echo将显示1.41421... 当我们从add函数返回了this指针时,我们可以将加法操作和mod()在一行中。

The third echo displays 4+3i. This is expected as we try to stringfy a complex number using our __toString() magic method. It casts a complex number to a string using the implementation we defined.

第三个echo显示4+3i 。 这是预期的,因为我们尝试使用__toString()魔术方法将复数字符串化。 它使用我们定义的实现将复数转换为字符串。

In the fourth echo, we will encounter an error because the parameter is not of type Complex (but a DateTime object). This shows the strict type checking in PHP-CPP when an object is passed: the object type must match the registered type.

在第四个echo ,我们将遇到一个错误,因为参数不是Complex类型(而是DateTime对象)。 这显示了传递对象时PHP-CPP中的严格类型检查:对象类型必须与注册的类型匹配。

包装在名称空间中 (Wrapping in a namespace)

Let’s wrap the class we just created into a namespace to have better encapsulation.

让我们将刚创建的类包装到命名空间中,以实现更好的封装。

This process is astonishingly simple and easy. We don’t need to change the class declaration/implementation at all. All we need to do is to change the registration process in get_module() function and it now looks like this:

这个过程非常简单和容易。 我们根本不需要更改类的声明/实现。 我们需要做的就是更改get_module()函数中的注册过程,现在看起来像这样:

extern "C" {

    PHPCPP_EXPORT void *get_module() {
        // create static instance of the extension object and the namespace instance
        static Php::Extension myExtension("complex", "1.0");

        Php::Namespace myNamespace("trComplex");

        // description of the class so that PHP knows which methods are accessible
        Php::Class<Complex> complex("Complex");

        // register the methods, and specify the parameters
        complex.method("mod", &Complex::mod, {});
        complex.method("__construct", &Complex::__construct);
        complex.method("add", &Complex::add, {
            Php::ByVal("op", "trComplex\\Complex", false, true)
        });

        // add the class to namespace
        myNamespace.add(std::move(complex));

        // add the namespace to the extension
        myExtension.add(std::move(myNamespace));

        // return the extension
        return myExtension;
    }

Instead of adding the class directly into the extension, we added one more namespace layer (named trComplex in this case). The class and its member registration remains almost identical except that in add function’s parameter declaration, we used trComplex\\Complex instead of Complex. Next, we moved the class into the namespace, and the namespace into the extension.

我们没有将类直接添加到扩展中,而是添加了一个名称空间层(在本例中为trComplex )。 该类及其成员注册几乎保持相同,除了在add函数的参数声明中,我们使用trComplex\\Complex而不是Complex 。 接下来,我们将类移至名称空间,并将名称空间移至扩展。

To test the new namespace and class, we can modify the testing snippets:

为了测试新的名称空间和类,我们可以修改测试片段:

<?php

$c=new trComplex\Complex(-3,-4);
echo $c->mod()."\n";

$d=new trComplex\Complex(4,3);

echo $c->add($d)->mod()."\n";

echo ((string)$d."\n");

$f=new \DateTime();
$g=$d->add($f); //Error!

Instead of just using Complex, we now use trComplex\Complex (the fully qualified name of this class) to declare the variables. The output will be the same as the previous demo. It shows that a PHP-CPP namespace is identical to a natural PHP namespace.

现在,我们不只是使用Complex ,而是使用trComplex\Complex ( trComplex\Complex的完全限定名称)来声明变量。 输出将与先前的演示相同。 它表明PHP-CPP命名空间与自然PHP命名空间相同。

最后的想法 (Final thoughts)

PHP-CPP is very powerful and easy to use. I do hope that after these two parts of discussion, users will find it a promising library to help develop PHP extensions using familiar C++ syntax and semantics.

PHP-CPP非常强大且易于使用。 我确实希望在这两部分讨论之后,用户会发现它是一个很有前途的库,可以帮助您使用熟悉的C ++语法和语义开发PHP扩展。

There are a few areas for improvement, though.

不过,仍有一些需要改进的地方。

First of all, its documentation needs more insightful API explanations. For example, we see earlier that the implementation() method is not covered in its current online documentation. This should not be the case. Users need step-by-step instructions and demos (which are now in its official documentation), but also need a full API reference.

首先,其文档需要更深入的API说明。 例如,我们较早时看到在当前的在线文档中未涉及implementation()方法。 事实并非如此。 用户需要逐步的说明和演示(现在在其官方文档中),但也需要完整的API参考。

Secondly, we do hope its 1.0 major release will come as soon as possible. In my testing, some funny segmentation errors popped up and after upgrading to the latest version, these errors disappeared; but we do need a stable 1.0 version.

其次,我们希望它的1.0主要版本会尽快出现。 在我的测试中,弹出了一些有趣的细分错误,升级到最新版本后,这些错误消失了; 但是我们确实需要一个稳定的1.0版本。

Third, even though in the last echo in our demo, PHP prompts: “PHP Catchable fatal error: Argument 1 passed to Complex::add() must be an instance of Complex, instance of DateTime given…”, this error is not catchable in a try...catch block in PHP. This is a bit annoying.

第三,即使在我们的演示中的最后echo中,PHP仍会提示:“ PHP可捕获的致命错误:传递给Complex :: add()的参数1必须是Complex的实例,给定了DateTime的实例……”,该错误无法捕获。在PHP的try...catch块中。 这有点烦人。

In this Part 2 on PHP-CPP, we covered several important aspects: class and member functions, magic methods, namespace encapsulation, etc.

在PHP-CPP的第2部分中,我们涵盖了几个重要方面:类和成员函数,魔术方法,名称空间封装等。

I would recommend PHP-CPP as the development tool to develop PHP extensions. Its advantages are obvious: fast learning curve, familiar C++ syntax, PHP magic methods support, OO features, etc.

我建议将PHP-CPP作为开发工具来开发PHP扩展。 它的优点是显而易见的:快速学习曲线,熟悉的C ++语法,支持PHP魔术方法,OO功能等等。

Feel free to comment and let us know your thoughts!

随时发表评论,让我们知道您的想法!

翻译自: https://www.sitepoint.com/php-extension-development-php-cpp-object-oriented-code/

cpp 面向对象小题目

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值