Skip to content

Commit

Permalink
fixed conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
EmielBruijntjes committed Aug 26, 2014
2 parents a286c34 + 97bc675 commit f526c4c
Show file tree
Hide file tree
Showing 35 changed files with 1,164 additions and 142 deletions.
36 changes: 36 additions & 0 deletions documentation/extension-callbacks.html
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,42 @@ <h1>Extension callbacks</h1>
right before PHP shuts down. If there is anything to clean up, you can install
such a callback and run the cleanup code from it.
</p>
<h2 id="apache-prefork-module">Forked engines (like Apache)</h2>
<p>
If you run PHP on a pre-fork web server (like Apache), your extension is
loaded and initialized <i>before</i> the various worker threads are
forked off. The consequence of this is that the get_module() function
and your optional onStartup() callback function are called by the parent
process, and all other callbacks and the actual page handling by the
child processes. A call to getpid() (or other functions to retrieve
information about the current process) will therefore return something
else inside the onStartup callback, as it does in any of the other
extension functions.
</p>
<p>
You may have to be careful because of this. It is better not to
do things in the startup functions that may not work when the process
is forked into different child processes (like opening file descriptors).
Something else to keep in mind is that the startup function is only called
by the parent processes when Apache starts up (or reloaded, see later),
while the shutdown function is called by <i>every</i> child process
that gracefully exits. The onShutdown is thus not only called when the
Apache process is stopped, but also when one of the worker processes
exits because it no longer is needed, or because it is replaced by
a fresh and new worker.
</p>
<p>
The get_module() function - as you've seen countles times before - is
called when your extension is initially loaded. But not only then. When
apache is reloaded (for example by giving the command line instruction
"apachectl reload"), your get_module() gets called for a second time,
and the callback that you registered with Extension::onStartup() is
called again too.
This is normally not a problem, because the static extension object is
in a locked state after the first get_module() call, and the functions
and classes that you try to add to the extension object in the second
invokation of get_module() are simply ignored.
</p>
<h2 id="multi-threading">Watch out for multi-threading</h2>
<p>
If your extension runs on a multi-threaded PHP installation, you need to take
Expand Down
2 changes: 1 addition & 1 deletion documentation/ten-reasons-for-using-php-cpp.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ <h4>7. Proven technology</h4>
C++ is a proven language with a more than 40 year long history. C++ has an
official open standard and is controlled by a C++ standards committee with
members that have proven track records. Compilers have been developed by companies
like Microsoft, IBM, Intel, Apple and there there are several open source
like Microsoft, IBM, Intel, Apple and there are several open source
compilers available (GNU, CLANG), so you can always switch to a faster or
more stable alternative. The compiler vendors are constantly motivated to
be better than their competitors and bring out new versions of their compilers
Expand Down
6 changes: 3 additions & 3 deletions documentation/variables.html
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,10 @@ <h2 id="strings">Strings</h2>
// result variable
Php::Value result;

// resize the buffer to 4096 bytes, the resize() method resizes
// resize the buffer to 4096 bytes, the reserve() method resizes
// the internal buffer to the appropriate size, and returns a pointer
// to the buffer
char *buffer = result.resize(4096);
char *buffer = result.reserve(4096);

// read in the bytes directly into the just allocated buffer
ssize_t bytes = read(fd, buffer, 4096);
Expand All @@ -235,7 +235,7 @@ <h2 id="strings">Strings</h2>
// resize the buffer to the actual number of bytes in it (this
// is necessary, otherwise the PHP strlen() returns 4096 even
// when less bytes were available
result.resize(bytes);
result.reserve(bytes);

// return the result
return result;
Expand Down
10 changes: 5 additions & 5 deletions include/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class Array : public Value
Array(const Value &value) : Value(value)
{
// type must be valid
if (value.type() != Type::Array) throw Php::Exception("Assigning a non-array to an array variable");
if (value.type() != Type::Array) throw FatalError("Assigning a non-array to an array variable");
}

/**
Expand All @@ -41,7 +41,7 @@ class Array : public Value
Array(Value &&value) : Value(std::move(value))
{
// type must be valid
if (value.type() != Type::Array) throw Php::Exception("Moving a non-array to an array variable");
if (value.type() != Type::Array) throw FatalError("Moving a non-array to an array variable");
}

/**
Expand Down Expand Up @@ -76,7 +76,7 @@ class Array : public Value
virtual Value &setType(Type type) override
{
// throw exception if things are going wrong
if (type != Type::Array) throw Php::Exception("Changing type of a fixed array variable");
if (type != Type::Array) throw FatalError("Changing type of a fixed array variable");

// call base
return Value::setType(Type::Array);
Expand All @@ -93,7 +93,7 @@ class Array : public Value
if (this == &value) return *this;

// type must be valid
if (value.type() != Type::Array) throw Php::Exception("Assigning a non-array to a fixed array variable");
if (value.type() != Type::Array) throw FatalError("Assigning a non-array to a fixed array variable");

// call base
Value::operator=(value);
Expand All @@ -113,7 +113,7 @@ class Array : public Value
if (this == &value) return *this;

// type must be valid
if (value.type() != Type::Array) throw Php::Exception("Moving a non-array to a fixed array variable");
if (value.type() != Type::Array) throw FatalError("Moving a non-array to a fixed array variable");

// call base
Value::operator=(std::move(value));
Expand Down
15 changes: 15 additions & 0 deletions include/call.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@
*/
namespace Php {

/**
* List of functions that are available for use in PHP
*/
extern bool class_exists(const char *classname, size_t size, bool autoload = true);
inline bool class_exists(const char *classname, bool autoload = true) { return class_exists(classname, strlen(classname), autoload); }
inline bool class_exists(const std::string &classname, bool autoload = true) { return class_exists(classname.c_str(), classname.size(), autoload); }
extern Value eval(const std::string &phpCode);
inline bool is_a(const Value &obj, const char *classname, size_t size, bool allow_string = false) { return obj.instanceOf(classname, size, allow_string); }
inline bool is_a(const Value &obj, const char *classname, bool allow_string = false) { return is_a(obj, classname, strlen(classname), allow_string); }
inline bool is_a(const Value &obj, const std::string &classname, bool allow_string = false) { return is_a(obj, classname.c_str(), classname.size(), allow_string); }
inline bool is_subclass_of(const Value &obj, const char *classname, size_t size, bool allow_string = true) { return obj.derivedFrom(classname, size, allow_string); }
inline bool is_subclass_of(const Value &obj, const char *classname, bool allow_string = true) { return is_subclass_of(obj, classname, strlen(classname), allow_string); }
inline bool is_subclass_of(const Value &obj, const std::string &classname, bool allow_string = true) { return is_subclass_of(obj, classname.c_str(), classname.size(), allow_string); }


/**
* Call a function in PHP
* @param name Name of the function to call
Expand Down
30 changes: 28 additions & 2 deletions include/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,14 +201,40 @@ class Class : private ClassBase
Class<T> &extends(const Class<CLASS> &base) { ClassBase::extends(base); return *this; }

private:
/**
* Method to create the object if it is default constructable
* @param orig
* @return Base*
*/
template <typename X = T>
typename std::enable_if<std::is_default_constructible<X>::value, Base*>::type
static maybeConstruct()
{
// create a new instance
return new X();
}

/**
* Method to create the object if it is not default constructable
* @param orig
* @return Base*
*/
template <typename X = T>
typename std::enable_if<!std::is_default_constructible<X>::value, Base*>::type
static maybeConstruct()
{
// create empty instance
return nullptr;
}

/**
* Construct a new instance of the object
* @return Base
*/
virtual Base* construct() const override
{
// construct an instance
return new T();
return maybeConstruct<T>();
}

/**
Expand All @@ -225,7 +251,7 @@ class Class : private ClassBase
}

/**
* Method to clone the object if it is copy constructable
* Method to clone the object if it is not copy constructable
* @param orig
* @return Base*
*/
Expand Down
4 changes: 2 additions & 2 deletions include/classbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
* ClassBase.h
*
* This is the base class of the "Class" class. This is an internal class that
* is used by the PHP-CPP library. But because the constructor is protected,
* is used by the PHP-CPP library. Because the constructor is protected,
* you can not create any instances if this class yourself (and you are not
* supposed to do that either.
* supposed to do that either).
*
* Further more, because this base class is a 'private' base of Class, all
* features of it are normally also inaccessible.
Expand Down
10 changes: 10 additions & 0 deletions include/exception.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ class Exception : public std::exception
// yes, it is native
return true;
}

/**
* Report this error as a fatal error
* @return bool
*/
virtual bool report() const
{
// this is not done here
return false;
}
};

/**
Expand Down
16 changes: 16 additions & 0 deletions include/extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ class Extension : public Namespace
*/
Extension &add(Ini &&ini)
{
// skip when locked
if (locked()) return *this;

// and add it to the list of classes
_ini_entries.emplace_back(new Ini(std::move(ini)));

Expand All @@ -125,6 +128,9 @@ class Extension : public Namespace
*/
Extension &add(const Ini &ini)
{
// skip when locked
if (locked()) return *this;

// and add it to the list of classes
_ini_entries.emplace_back(new Ini(ini));

Expand Down Expand Up @@ -180,6 +186,16 @@ class Extension : public Namespace
{
return module();
}

protected:
/**
* Is the extension object in a locked state? This happens after the
* get_module() function was called for the first time ("apache reload"
* forces a new call to get_module())
*
* @return bool
*/
virtual bool locked() const override;

private:
/**
Expand Down
66 changes: 66 additions & 0 deletions include/fatalerror.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* FatalError.h
*
*
* Normally, fatal errors are reported with a call to zend_error().
*
* However, this will trigger a longjmp(), which will cause objects
* constructed in the extension not to be destructed. We use therefore
* this FatalError class, which is a normally exception that _does_
* cause objects to be destructed.
*
* When it is caught, right before control is handed back to the Zend
* engine, it will turn the exception into a zend_error() call and
* thus a longjmp.
*
* @author Emiel Bruijntjes <[email protected]>
* @copyright 2014 Copernica BV
*/

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

/**
* Class definition
*/
class FatalError : public Exception
{
public:
/**
* Constructor
* @param message
*/
FatalError(const std::string &message) : Exception(message) {}

/**
* Destructor
*/
virtual ~FatalError() throw()
{
}

/**
* Is this a native exception (one that was thrown from C++ code)
* @return bool
*/
virtual bool native() const
{
// although it is native, we return 0 because it should not persist
// as exception, but it should live on as zend_error() in stead
return false;
}

/**
* Report this error as a fatal error
* @return bool
*/
virtual bool report() const override;
};

/**
* End of namespace
*/
}

Loading

0 comments on commit f526c4c

Please sign in to comment.