Map known PHP interfaces to zend_class_entry*
Most pre-defined interfaces are accessible via zend_class_entry* variables declared in the PHP C API - we can use these to add an interface at MINIT time (rather than having to wait until RINIT to look up by name) by having a mapping from PHP interface name to them. This will also be a little faster than looking up by name. Closes #2013
This commit is contained in:
parent
e82725b22e
commit
3c168ef332
4 changed files with 124 additions and 19 deletions
|
|
@ -547,3 +547,6 @@
|
||||||
|
|
||||||
/* php keywords */
|
/* php keywords */
|
||||||
%include <phpkw.swg>
|
%include <phpkw.swg>
|
||||||
|
|
||||||
|
/* PHP known interfaces */
|
||||||
|
%include <phpinterfaces.i>
|
||||||
|
|
|
||||||
62
Lib/php/phpinterfaces.i
Normal file
62
Lib/php/phpinterfaces.i
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* phpinterfaces.i
|
||||||
|
*
|
||||||
|
* Define "known" PHP interfaces.
|
||||||
|
*
|
||||||
|
* These can be added at MINIT time (which is when PHP loads the extension
|
||||||
|
* module).
|
||||||
|
*
|
||||||
|
* Any interface can be added via phpinterfaces, but looking up the
|
||||||
|
* zend_class_entry by name has to wait until RINIT time, which means it
|
||||||
|
* happens for every request.
|
||||||
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
// Note: Abstract interfaces such as "Traversable" can't be used in
|
||||||
|
// "implements" so are not relevant here.
|
||||||
|
|
||||||
|
%insert(header) %{
|
||||||
|
|
||||||
|
#define SWIG_PHP_INTERFACE_Iterator_CE zend_ce_iterator
|
||||||
|
#define SWIG_PHP_INTERFACE_Iterator_HEADER "zend_interfaces.h"
|
||||||
|
|
||||||
|
#define SWIG_PHP_INTERFACE_IteratorAggregate_CE zend_ce_aggregate
|
||||||
|
#define SWIG_PHP_INTERFACE_IteratorAggregate_HEADER "zend_interfaces.h"
|
||||||
|
|
||||||
|
#define SWIG_PHP_INTERFACE_ArrayAccess_CE zend_ce_arrayaccess
|
||||||
|
#define SWIG_PHP_INTERFACE_ArrayAccess_HEADER "zend_interfaces.h"
|
||||||
|
|
||||||
|
#define SWIG_PHP_INTERFACE_Serializable_CE zend_ce_serializable
|
||||||
|
#define SWIG_PHP_INTERFACE_Serializable_HEADER "zend_interfaces.h"
|
||||||
|
|
||||||
|
#define SWIG_PHP_INTERFACE_Countable_CE zend_ce_countable
|
||||||
|
#define SWIG_PHP_INTERFACE_Countable_HEADER "zend_interfaces.h"
|
||||||
|
|
||||||
|
#define SWIG_PHP_INTERFACE_OuterIterator_CE spl_ce_OuterIterator
|
||||||
|
#define SWIG_PHP_INTERFACE_OuterIterator_HEADER "ext/spl/spl_iterators.h"
|
||||||
|
|
||||||
|
#define SWIG_PHP_INTERFACE_RecursiveIterator_CE spl_ce_RecursiveIterator
|
||||||
|
#define SWIG_PHP_INTERFACE_RecursiveIterator_HEADER "ext/spl/spl_iterators.h"
|
||||||
|
|
||||||
|
#define SWIG_PHP_INTERFACE_SeekableIterator_CE spl_ce_SeekableIterator
|
||||||
|
#define SWIG_PHP_INTERFACE_SeekableIterator_HEADER "ext/spl/spl_iterators.h"
|
||||||
|
|
||||||
|
#define SWIG_PHP_INTERFACE_SplObserver_CE spl_ce_SplObserver
|
||||||
|
#define SWIG_PHP_INTERFACE_SplObserver_HEADER "ext/spl/spl_observer.h"
|
||||||
|
|
||||||
|
#define SWIG_PHP_INTERFACE_SplSubject_CE spl_ce_SplSubject
|
||||||
|
#define SWIG_PHP_INTERFACE_SplSubject_HEADER "ext/spl/spl_observer.h"
|
||||||
|
|
||||||
|
#define SWIG_PHP_INTERFACE_DateTimeInterface_CE php_date_get_interface_ce()
|
||||||
|
#define SWIG_PHP_INTERFACE_DateTimeInterface_HEADER "ext/date/php_date.h"
|
||||||
|
|
||||||
|
// The "json" extension needs to be loaded earlier that us for this to work.
|
||||||
|
#define SWIG_PHP_INTERFACE_JsonSerializable_CE php_json_serializable_ce
|
||||||
|
#define SWIG_PHP_INTERFACE_JsonSerializable_HEADER "ext/json/php_json.h"
|
||||||
|
|
||||||
|
// New in PHP 8.0.
|
||||||
|
#if PHP_MAJOR >= 8
|
||||||
|
# define SWIG_PHP_INTERFACE_Stringable_CE zend_ce_stringable
|
||||||
|
# define SWIG_PHP_INTERFACE_Stringable_HEADER "zend_interfaces.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
@ -16,7 +16,9 @@ extern "C" {
|
||||||
# error These bindings need PHP 7 or later - to generate PHP5 bindings use: SWIG < 4.0.0 and swig -php5
|
# error These bindings need PHP 7 or later - to generate PHP5 bindings use: SWIG < 4.0.0 and swig -php5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "zend_inheritance.h"
|
||||||
#include "zend_exceptions.h"
|
#include "zend_exceptions.h"
|
||||||
|
#include "zend_inheritance.h"
|
||||||
|
|
||||||
#include <stdlib.h> /* for abort(), used in generated code. */
|
#include <stdlib.h> /* for abort(), used in generated code. */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1635,26 +1635,64 @@ public:
|
||||||
Setline(node, Getline(n));
|
Setline(node, Getline(n));
|
||||||
String *interfaces = Swig_typemap_lookup("phpinterfaces", node, "", 0);
|
String *interfaces = Swig_typemap_lookup("phpinterfaces", node, "", 0);
|
||||||
Replaceall(interfaces, " ", "");
|
Replaceall(interfaces, " ", "");
|
||||||
if (interfaces) {
|
if (interfaces && Len(interfaces) > 0) {
|
||||||
// It seems we need to wait until RINIT time to look up classes.
|
// It seems we need to wait until RINIT time to look up class entries
|
||||||
// The downside is that this then happens for every request.
|
// for interfaces by name. The downside is that this then happens for
|
||||||
Printf(r_init, "{\n");
|
// every request.
|
||||||
|
//
|
||||||
|
// Most pre-defined interfaces are accessible via zend_class_entry*
|
||||||
|
// variables declared in the PHP C API - these we can use at MINIT
|
||||||
|
// time, so we special case them. This will also be a little faster
|
||||||
|
// than looking up by name.
|
||||||
|
Printv(s_header,
|
||||||
|
"#ifdef __cplusplus\n",
|
||||||
|
"extern \"C\" {\n",
|
||||||
|
"#endif\n",
|
||||||
|
NIL);
|
||||||
|
|
||||||
|
String *r_init_prefix = NewStringEmpty();
|
||||||
|
|
||||||
List *interface_list = Split(interfaces, ',', -1);
|
List *interface_list = Split(interfaces, ',', -1);
|
||||||
int num_interfaces = Len(interface_list);
|
int num_interfaces = Len(interface_list);
|
||||||
String *append_interface = NewStringEmpty();
|
for (int i = 0; i < num_interfaces; ++i) {
|
||||||
for(int Iterator = 1; Iterator <= num_interfaces; Iterator++) {
|
String *interface = Getitem(interface_list, i);
|
||||||
String *interface = Getitem(interface_list, Iterator-1);
|
// We generate conditional code in both minit and rinit - then we or the user
|
||||||
String *interface_ce = NewStringEmpty();
|
// just need to define SWIG_PHP_INTERFACE_xxx_CE (and optionally
|
||||||
Printf(interface_ce, "php_%s_interface_ce_%d" , class_name , Iterator);
|
// SWIG_PHP_INTERFACE_xxx_CE) to handle interface `xxx` at minit-time.
|
||||||
Printf(r_init, " zend_class_entry *%s = zend_lookup_class(zend_string_init(\"%s\", sizeof(\"%s\") - 1, 0));\n", interface_ce, interface, interface);
|
Printv(s_header,
|
||||||
Append(append_interface, interface_ce);
|
"#ifdef SWIG_PHP_INTERFACE_", interface, "_HEADER\n",
|
||||||
Append(append_interface, " ");
|
"# include SWIG_PHP_INTERFACE_", interface, "_HEADER\n",
|
||||||
|
"#endif\n",
|
||||||
|
NIL);
|
||||||
|
Printv(s_oinit,
|
||||||
|
"#ifdef SWIG_PHP_INTERFACE_", interface, "_CE\n",
|
||||||
|
" zend_do_implement_interface(SWIGTYPE_", class_name, "_ce, SWIG_PHP_INTERFACE_", interface, "_CE);\n",
|
||||||
|
"#endif\n",
|
||||||
|
NIL);
|
||||||
|
Printv(r_init_prefix,
|
||||||
|
"#ifndef SWIG_PHP_INTERFACE_", interface, "_CE\n",
|
||||||
|
" {\n",
|
||||||
|
" zend_class_entry *swig_interface_ce = zend_lookup_class(zend_string_init(\"", interface, "\", sizeof(\"", interface, "\") - 1, 0));\n",
|
||||||
|
" if (!swig_interface_ce) zend_throw_exception(zend_ce_error, \"Interface \\\"", interface, "\\\" not found\", 0);\n",
|
||||||
|
" zend_do_implement_interface(SWIGTYPE_", class_name, "_ce, swig_interface_ce);\n",
|
||||||
|
" }\n",
|
||||||
|
"#endif\n",
|
||||||
|
NIL);
|
||||||
}
|
}
|
||||||
Chop(append_interface);
|
|
||||||
Replaceall(append_interface, " ", ",");
|
// Handle interfaces at the start of rinit so that they're added
|
||||||
Printf(r_init, " zend_class_implements(SWIGTYPE_%s_ce, %d, %s);\n", class_name, num_interfaces, append_interface);
|
// before any potential constant objects, etc which might be created
|
||||||
Printf(r_init, "}\n");
|
// later in rinit.
|
||||||
|
Insert(r_init, 0, r_init_prefix);
|
||||||
|
Delete(r_init_prefix);
|
||||||
|
|
||||||
|
Printv(s_header,
|
||||||
|
"#ifdef __cplusplus\n",
|
||||||
|
"}\n",
|
||||||
|
"#endif\n",
|
||||||
|
NIL);
|
||||||
}
|
}
|
||||||
|
Delete(interfaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
Printf(s_oinit, " SWIGTYPE_%s_ce->create_object = %s_object_new;\n", class_name, class_name);
|
Printf(s_oinit, " SWIGTYPE_%s_ce->create_object = %s_object_new;\n", class_name, class_name);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue