summaryrefslogtreecommitdiff
path: root/include/object.h
blob: 745b7c6a9b1b602a108590f467332ac8bf0f0611 (plain)
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/**
 *  Object.h
 *
 *  Extended Value that can be used to instantiate new objects, and to turn
 *  Php::Base objects into regular Php::Value instances
 *
 *  @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
 *  @copyright 2014 Copernica BV
 */

/**
 *  Set up namespace
 */
namespace Php {

/**
 *  Class definition
 */
class PHPCPP_EXPORT Object : public Value
{
public:
    /**
     *  Constructor for an empty stdClass object
     */
    Object() : Value(Type::Object) {}

    /**
     *  Copy constructor is valid if the passed in object is also an object,
     *  or when it is a string holding a classname
     *  @param  that        An other object
     */
    Object(const Value &value);

    /**
     *  Constructor to create a new instance of a builtin class
     *
     *  You can use this constructor if you have created an instance of your
     *  own class, but has not assigned it to a variable yet. This happens
     *  for example for classes that are not constructed from PHP userspace,
     *  but from your own functions:
     *
     *  Php::Value yourFunction()
     *  {
     *      return Php::Object("MyClass", new MyClass());
     *  }
     *
     *  When you construct objects like this, the __construct function is not
     *  going to be called. If you want to construct the object just as if it
     *  was constructed from PHP user space, do this:
     *
     *  Php::Value yourFunction()
     *  {
     *      return Php::Object("MyClass");
     *  }
     *
     *  @param  name        Name of the class to instantiate
     *  @param  base        C++ object to wrap
     */
    Object(const char *name, Base *base);

    /**
     *  If you already have the zend_class_entry, you can also pass the
     *  class_entry structure instead of the class name. This constructor
     *  works exactly like the Object(name, base) constructor mentioned
     *  above.
     *
     *  Note that if you normally use PHP-CPP, you do not have the class_entry,
     *  so you probably need to pass the name anyway
     *
     *  @param  entry       The PHP class entry
     *  @param  base        C++ object to wrap
     */
    Object(struct _zend_class_entry *entry, Base *base);

    /**
     *  Wrap around an object implemented by us
     *  @param  object      Object to be wrapped
     */
    Object(Base *base) : Value(base) {}

    /**
     *  Constructor to create a new instance
     *  @param  name        Name of the class to instantiate
     */
    Object(const char *name) : Value() { if (instantiate(name)) call("__construct"); }

    /**
     *  Constructor to create a new instance
     *
     *  Note that it was not possible to create a constructor with signature
     *  Object(const char *name, Args&&... args) because that overrides the
     *  Object(const char *name, Base *base) constructor.
     *
     *  @param  name        Name of the class to instantiate
     *  @param  args        Optional arguments
     */
    template <typename ...Args>
    Object(const char *name, Value arg0, Args&&... args) : Value() { if (instantiate(name)) call("__construct", arg0, std::forward<Value>(args)...); }

    /**
     *  Destructor
     */
    virtual ~Object() {}

    /**
     *  Change the internal type of the variable
     *  @param  Type
     */
    virtual Value &setType(Type type) override
    {
        // throw exception if things are going wrong
        if (type != Type::Object) throw FatalError("Changing type of a fixed object variable");

        // call base
        return Value::setType(type);
    }

    /**
     *  Assignment operator
     *  @param  value
     *  @return ForcedValue
     */
    Object &operator=(const Value &value)
    {
        // skip self assignment
        if (this == &value) return *this;

        // type must be valid
        if (value.type() != Type::Object) throw FatalError("Assigning a non-object to an object variable");

        // call base
        Value::operator=(value);

        // done
        return *this;
    }

    /**
     *  Move assignment operator
     *  @param  value
     *  @return ForcedValue
     */
    Object &operator=(Value &&value)
    {
        // skip self assignment
        if (this == &value) return *this;

        // type must be valid
        if (value.type() != Type::Object) throw FatalError("Moving a non-object to an object variable");

        // call base
        Value::operator=(std::move(value));

        // done
        return *this;
    }

private:
    /**
     *  Helper method to instantiate an object
     *
     *  This method returns true if there is a __construct() function, and
     *  false otherwise
     *
     *  @param  name        Class name
     *  @return bool
     */
    bool instantiate(const char *name);
};

/**
 *  End namespace
 */
}