Patch spl-classloader for SPL related Bug #60128
Patch version 2011-10-25 10:18 UTC
Return to Bug #60128 |
Download this patch
Patch Revisions:
Developer: davidc@php.net
Index: ext/spl/spl_classloader.c
===================================================================
--- ext/spl/spl_classloader.c (revision 0)
+++ ext/spl/spl_classloader.c (revision 0)
@@ -0,0 +1,464 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2009 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: metagoto <runpac314@gmail.com> |
+ | David Coallier <davidc@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "zend_interfaces.h"
+
+#include "spl_classloader.h"
+
+#include "php_spl.h"
+#include "spl_engine.h"
+#include "spl_functions.h"
+#include "spl_exceptions.h"
+
+zend_object_handlers spl_handler_SplClassLoader;
+PHPAPI zend_class_entry *spl_ce_SplClassLoader;
+
+/* zend_API.h: #define ZEND_NS_NAME(ns, name) ns"\\"name */
+#define SPL_CLASSLD_NS_SEPARATOR '\\'
+
+
+static zend_class_entry* spl_classloader_ce;
+zend_object_handlers spl_SplClassLoader_handlers;
+
+
+typedef struct _spl_SplClassLoader {
+ zend_object std;
+ char* ns;
+ int ns_len;
+ char* inc_path;
+ int inc_path_len;
+ char* file_ext;
+ int file_ext_len;
+} spl_SplClassLoader;
+
+
+static void spl_SplClassLoader_dtor(void* object, zend_object_handle handle TSRMLS_DC)
+{
+ spl_SplClassLoader* obj = (spl_SplClassLoader*)object;
+ if (obj->ns) {
+ efree(obj->ns);
+ obj->ns = NULL;
+ }
+ if (obj->inc_path) {
+ efree(obj->inc_path);
+ obj->inc_path = NULL;
+ }
+ if (obj->file_ext) {
+ efree(obj->file_ext);
+ obj->file_ext = NULL;
+ }
+ zend_object_std_dtor(&obj->std TSRMLS_CC);
+ efree(obj);
+}
+
+
+zend_object_value spl_object_classloader_new_ex(zend_class_entry *class_type, spl_SplClassLoader **obj, zval *orig TSRMLS_DC) /* {{{ */
+{
+ zend_object_value retval;
+ spl_SplClassLoader *intern;
+
+ intern = emalloc(sizeof(spl_SplClassLoader));
+ memset(intern, 0, sizeof(spl_SplClassLoader));
+ *obj = intern;
+
+ zend_object_std_init(&intern->std, class_type TSRMLS_CC);
+ object_properties_init(&intern->std, class_type);
+
+ //zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void*)NULL, sizeof(zval*));
+
+ intern->file_ext = estrndup(".php", sizeof(".php")-1);
+ intern->file_ext_len = sizeof(".php")-1;
+
+ retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (void*)spl_SplClassLoader_dtor, NULL TSRMLS_CC);
+ retval.handlers = &spl_SplClassLoader_handlers;
+
+ return retval;
+} /* }}} */
+
+/* {{{ spl_SplClassLoader_new */
+static zend_object_value spl_SplClassLoader_new(zend_class_entry *class_type TSRMLS_DC)
+{
+ spl_SplClassLoader *tmp;
+ return spl_object_classloader_new_ex(class_type, &tmp, NULL TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto void SplClassLoader::__construct([string $namespace [, string $include_path]])
+ Constructor */
+SPL_METHOD(SplClassLoader, __construct)
+{
+ char* ns = NULL;
+ int ns_len = 0;
+ char* inc_path = NULL;
+ int inc_path_len = 0;
+ spl_SplClassLoader* obj;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &ns, &ns_len, &inc_path, &inc_path_len) == FAILURE) {
+ return; /* should throw ? */
+ }
+
+ obj = (spl_SplClassLoader *) zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (ns_len) {
+ obj->ns = estrndup(ns, ns_len);
+ obj->ns_len = ns_len;
+ }
+
+ if (inc_path_len) {
+ obj->inc_path = estrndup(inc_path, inc_path_len);
+ obj->inc_path_len = inc_path_len;
+ }
+} /* }}} */
+
+/* {{{ proto bool SplClassLoader::register()
+ Installs this class loader on the SPL autoload stack */
+SPL_METHOD(SplClassLoader, register)
+{
+ zval* arr;
+ zval* retval = NULL;
+ zval* pthis = getThis();
+ int res = 0;
+
+ MAKE_STD_ZVAL(arr);
+ array_init(arr);
+ Z_ADDREF_P(pthis);
+
+ add_next_index_zval(arr, pthis);
+ add_next_index_string(arr, estrndup("loadClass", sizeof("loadClass")-1), 0);
+
+ zend_call_method_with_1_params(NULL, NULL, NULL, "spl_autoload_register", &retval, arr);
+
+ zval_ptr_dtor(&arr);
+
+ if (retval) {
+ res = i_zend_is_true(retval);
+ zval_ptr_dtor(&retval);
+ }
+ RETURN_BOOL(res);
+} /* }}} */
+
+/* {{{ proto bool SplClassLoader::unregister()
+ Uninstalls this class loader from the SPL autoloader stack */
+SPL_METHOD(SplClassLoader, unregister)
+{
+ zval* arr;
+ zval* retval = NULL;
+ zval* pthis = getThis();
+ int res = 0;
+
+ MAKE_STD_ZVAL(arr);
+ array_init(arr);
+ Z_ADDREF_P(pthis);
+
+ add_next_index_zval(arr, pthis);
+ add_next_index_string(arr, estrndup("loadClass", sizeof("loadClass")-1), 0);
+
+ zend_call_method_with_1_params(NULL, NULL, NULL, "spl_autoload_unregister", &retval, arr);
+
+ zval_ptr_dtor(&arr);
+
+ if (retval) {
+ res = i_zend_is_true(retval);
+ zval_ptr_dtor(&retval);
+ }
+
+ RETURN_BOOL(res);
+} /* }}} */
+
+
+/* compute filename if (partial) ns and class match. returns filename len including '\0' or 0 */
+static int get_filename(spl_SplClassLoader* obj, char* cl, int cl_len, char* filename TSRMLS_DC)
+{
+ char* ccl = cl;
+ char* cns = obj->ns;
+ char* cur = &cl[cl_len-1];
+ int len = 0;
+
+ if (cl_len < obj->ns_len) {
+ return 0;
+ }
+
+ /* we have a ns to compare to the qualified class name */
+ if (obj->ns) {
+ int i = 0; /* compare and transform ns separator in place */
+ for ( ; i < obj->ns_len; ++i) {
+ if (*cns != *ccl) {
+ return 0;
+ }
+ if (*ccl == SPL_CLASSLD_NS_SEPARATOR) {
+ *ccl = PHP_DIR_SEPARATOR;
+ }
+ ++ccl;
+ ++cns;
+ }
+ if (*ccl != SPL_CLASSLD_NS_SEPARATOR) {
+ return 0;
+ }
+ *ccl = PHP_DIR_SEPARATOR;
+ }
+
+ /* transform '_' in the class name from right to left */
+ for ( ; cur != ccl; --cur) {
+ if (*cur == SPL_CLASSLD_NS_SEPARATOR) {
+ break;
+ }
+ if (*cur == '_') {
+ *cur = PHP_DIR_SEPARATOR;
+ }
+ }
+
+ /* tranform the remaining ns separator from right to left */
+ for ( ; cur != ccl; --cur) {
+ if (*cur == SPL_CLASSLD_NS_SEPARATOR) {
+ *cur = PHP_DIR_SEPARATOR;
+ }
+ }
+
+ if (obj->inc_path) {
+ len = obj->inc_path_len + 1 + cl_len + obj->file_ext_len + 1;
+ if (len > MAXPATHLEN) {
+ return 0;
+ }
+ /* sprintf: we know the len */
+ sprintf(filename, "%s%c%s%s", obj->inc_path, PHP_DIR_SEPARATOR, cl, obj->file_ext);
+ return len;
+ }
+ len = cl_len + obj->file_ext_len + 1;
+ if (len > MAXPATHLEN) {
+ return 0;
+ }
+ /* sprintf: we know the len */
+ sprintf(filename, "%s%s", cl, obj->file_ext);
+ return len;
+}
+
+
+/* {{{ proto bool SplClassLoader::loadClass(string $class_name)
+ Loads the given class or interface */
+SPL_METHOD(SplClassLoader, loadClass)
+{
+ char* cl;
+ int cl_len = 0;
+ char filename[MAXPATHLEN];
+ int len = 0;
+ spl_SplClassLoader* obj;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s/", &cl, &cl_len) == FAILURE /* zval separation is required */
+ || !cl_len) {
+ return;
+ }
+
+ obj = (spl_SplClassLoader*) zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ len = get_filename(obj, cl, cl_len, filename TSRMLS_CC);
+ if (len) {
+ zend_file_handle fh;
+ fh.filename = filename;
+ fh.opened_path = NULL;
+ fh.free_filename = 0;
+ fh.type = ZEND_HANDLE_FILENAME;
+ zend_execute_scripts(ZEND_INCLUDE TSRMLS_CC, NULL, 1, &fh);
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+} /* }}} */
+
+/* {{{ proto bool SplClassLoader::setIncludePath(string $include_path)
+ Sets the base include path for all class files in the namespace of this class loader */
+SPL_METHOD(SplClassLoader, setIncludePath)
+{
+ char* inc_path;
+ int inc_path_len;
+ spl_SplClassLoader* obj;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &inc_path, &inc_path_len)== FAILURE) {
+ return;
+ }
+
+ obj = (spl_SplClassLoader*) zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->inc_path) {
+ efree(obj->inc_path);
+ obj->inc_path = NULL;
+ }
+
+ if (inc_path_len) {
+ obj->inc_path = estrndup(inc_path, inc_path_len);
+ }
+
+ obj->inc_path_len = inc_path_len;
+
+ RETURN_TRUE;
+} /* }}} */
+
+/* {{{ proto string SplClassLoader::getIncludePath()
+ Gets the base include path for all class files in the namespace of this class loader */
+SPL_METHOD(SplClassLoader, getIncludePath)
+{
+ spl_SplClassLoader* obj = (spl_SplClassLoader*) zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->inc_path) {
+ RETURN_STRINGL(obj->inc_path, obj->inc_path_len, 1);
+ }
+
+ RETURN_EMPTY_STRING();
+} /* }}} */
+
+/* {{{ proto bool SplClassLoader::setFileExtension(string $file_extension)
+ Sets the file extension of class files in the namespace of this class loader */
+SPL_METHOD(SplClassLoader, setFileExtension)
+{
+ char* ext;
+ int ext_len;
+ spl_SplClassLoader* obj;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &ext, &ext_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ obj = (spl_SplClassLoader*) zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->file_ext) {
+ efree(obj->file_ext);
+ obj->file_ext = NULL;
+ }
+
+ if (ext_len) {
+ obj->file_ext = estrndup(ext, ext_len);
+ }
+
+ obj->file_ext_len = ext_len;
+
+ RETURN_TRUE;
+} /* }}} */
+
+/* {{{ proto string SplClassLoader::getFileExtension()
+ Gets the file extension of class files in the namespace of this class loader */
+SPL_METHOD(SplClassLoader, getFileExtension)
+{
+ spl_SplClassLoader* obj = (spl_SplClassLoader*) zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (obj->file_ext) {
+ RETURN_STRINGL(obj->file_ext, obj->file_ext_len, 1);
+ }
+
+ RETURN_EMPTY_STRING();
+} /* }}} */
+
+/* {{{ proto mixed SplClassLoader::getPath(string $class_name)
+ Gets the path for the given class. Does not load anything. This is just a handy method */
+SPL_METHOD(SplClassLoader, getPath)
+{
+ char* cl;
+ int cl_len = 0;
+ char filename[MAXPATHLEN];
+ int len = 0;
+ spl_SplClassLoader* obj;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &cl, &cl_len) == FAILURE
+ || !cl_len) {
+ return;
+ }
+
+ obj = (spl_SplClassLoader*) zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ len = get_filename(obj, cl, cl_len, filename TSRMLS_CC);
+
+ if (len) {
+ RETURN_STRINGL(filename, --len, 1); /* cl_len > 0 and len includes '\0' */
+ }
+
+ RETURN_FALSE;
+} /* }}} */
+
+/* {{{ arginfo and function tables */
+ZEND_BEGIN_ARG_INFO(arginfo_spl_classloader___construct, 0)
+ ZEND_ARG_INFO(0, namespace)
+ ZEND_ARG_INFO(0, include_path)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_classloader_loadclass, 0, 0, 1)
+ ZEND_ARG_INFO(0, class_name)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_classloader_setincludepath, 0, 0, 1)
+ ZEND_ARG_INFO(0, path)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_spl_classloader_setfileextension, 0, 0, 1)
+ ZEND_ARG_INFO(0, file_ext)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_spl_cl_void, 0)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry spl_funcs_SplClassLoader[] = {
+ SPL_ME(SplClassLoader, __construct, arginfo_spl_classloader___construct, ZEND_ACC_PUBLIC)
+ SPL_ME(SplClassLoader, register, arginfo_spl_cl_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplClassLoader, unregister, arginfo_spl_cl_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplClassLoader, loadClass, arginfo_spl_classloader_loadclass, ZEND_ACC_PUBLIC)
+ SPL_ME(SplClassLoader, setIncludePath, arginfo_spl_classloader_setincludepath, ZEND_ACC_PUBLIC)
+ SPL_ME(SplClassLoader, getIncludePath, arginfo_spl_cl_void , ZEND_ACC_PUBLIC)
+ SPL_ME(SplClassLoader, setFileExtension, arginfo_spl_classloader_setfileextension, ZEND_ACC_PUBLIC)
+ SPL_ME(SplClassLoader, getFileExtension, arginfo_spl_cl_void, ZEND_ACC_PUBLIC)
+ SPL_ME(SplClassLoader, getPath, arginfo_spl_cl_void, ZEND_ACC_PUBLIC)
+ PHP_FE_END
+};
+
+/*const zend_function_entry spl_classloader_functions[] = {
+ {NULL, NULL, NULL}
+};*/
+/* }}} */
+
+/* {{{ PHP_M* */
+PHP_MINIT_FUNCTION(spl_classloader)
+{
+ REGISTER_SPL_STD_CLASS_EX(SplClassLoader, spl_SplClassLoader_new, spl_funcs_SplClassLoader)
+
+ memcpy(&spl_SplClassLoader_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ spl_SplClassLoader_handlers.clone_obj = NULL; /* no cloning! */
+
+ return SUCCESS;
+}
+
+PHP_MINFO_FUNCTION(spl_classloader)
+{
+ php_info_print_table_start ();
+ php_info_print_table_header(2, "SplClassLoader support", "enabled");
+ php_info_print_table_row (2, "Conformance", "PSR-0");
+ php_info_print_table_end ();
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: fdm=marker
+ * vim: noet sw=4 ts=4
+ */
Index: ext/spl/spl_classloader.h
===================================================================
--- ext/spl/spl_classloader.h (revision 0)
+++ ext/spl/spl_classloader.h (revision 0)
@@ -0,0 +1,40 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2009 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: metagoto <runpac314@gmail.com> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifndef SPL_CLASSLOADER_H
+#define SPL_CLASSLOADER_H
+
+#include "php.h"
+#include "php_spl.h"
+
+extern PHPAPI zend_class_entry *spl_ce_SplClassLoader;
+
+#ifdef ZTS
+#include "TSRM.h"
+#endif
+
+#ifdef ZTS
+#define SPL_CLASSLD_G(v) TSRMG(spl_classloader_globals_id, zend_spl_classloader_globals *, v)
+#else
+#define SPL_CLASSLD_G(v) (spl_classloader_globals.v)
+#endif
+
+PHP_MINIT_FUNCTION(spl_classloader);
+PHP_MINFO_FUNCTION(spl_classloader);
+
+#endif /* SPL_CLASSLOADER_H */
Index: ext/spl/config.w32
===================================================================
--- ext/spl/config.w32 (revision 318369)
+++ ext/spl/config.w32 (working copy)
@@ -1,7 +1,7 @@
// $Id$
// vim:ft=javascript
-EXTENSION("spl", "php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fixedarray.c", false /*never shared */);
+EXTENSION("spl", "php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fixedarray.c spl_classloader.c", false /*never shared */);
AC_DEFINE('HAVE_SPL', 1);
PHP_SPL="yes";
-PHP_INSTALL_HEADERS("ext/spl", "php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_dllist.h spl_heap.h spl_fixedarray.h");
+PHP_INSTALL_HEADERS("ext/spl", "php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_dllist.h spl_heap.h spl_fixedarray.h spl_classloader.h");
Index: ext/spl/config.m4
===================================================================
--- ext/spl/config.m4 (revision 318369)
+++ ext/spl/config.m4 (working copy)
@@ -1,6 +1,5 @@
dnl $Id$
dnl config.m4 for extension SPL
-
AC_MSG_CHECKING(whether zend_object_value is packed)
old_CPPFLAGS=$CPPFLAGS
CPPFLAGS="$INCLUDES -I$abs_srcdir $CPPFLAGS"
@@ -22,6 +21,6 @@
CPPFLAGS=$old_CPPFLAGS
AC_DEFINE_UNQUOTED(HAVE_PACKED_OBJECT_VALUE, $ac_result, [Whether struct _zend_object_value is packed])
AC_DEFINE(HAVE_SPL, 1, [Whether you want SPL (Standard PHP Library) support])
- PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fixedarray.c, no)
- PHP_INSTALL_HEADERS([ext/spl], [php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_dllist.h spl_heap.h spl_fixedarray.h])
+ PHP_NEW_EXTENSION(spl, php_spl.c spl_functions.c spl_engine.c spl_iterators.c spl_array.c spl_directory.c spl_exceptions.c spl_observer.c spl_dllist.c spl_heap.c spl_fixedarray.c spl_classloader.c, no)
+ PHP_INSTALL_HEADERS([ext/spl], [php_spl.h spl_array.h spl_directory.h spl_engine.h spl_exceptions.h spl_functions.h spl_iterators.h spl_observer.h spl_dllist.h spl_heap.h spl_fixedarray.h spl_classloader.h])
PHP_ADD_EXTENSION_DEP(spl, pcre, true)
Index: ext/spl/php_spl.c
===================================================================
--- ext/spl/php_spl.c (revision 318369)
+++ ext/spl/php_spl.c (working copy)
@@ -37,6 +37,7 @@
#include "spl_dllist.h"
#include "spl_fixedarray.h"
#include "spl_heap.h"
+#include "spl_classloader.h"
#include "zend_exceptions.h"
#include "zend_interfaces.h"
#include "ext/standard/php_rand.h"
@@ -255,6 +256,7 @@
SPL_ADD_CLASS(SplTempFileObject, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(UnderflowException, z_list, sub, allow, ce_flags); \
SPL_ADD_CLASS(UnexpectedValueException, z_list, sub, allow, ce_flags); \
+ SPL_ADD_CLASS(SplClassLoader, z_list, sub, allow, ce_flags); \
/* {{{ proto array spl_classes()
Return an array containing the names of all clsses and interfaces defined in SPL */
@@ -1038,6 +1040,7 @@
PHP_MINIT(spl_heap)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(spl_fixedarray)(INIT_FUNC_ARGS_PASSTHRU);
PHP_MINIT(spl_observer)(INIT_FUNC_ARGS_PASSTHRU);
+ PHP_MINIT(spl_classloader)(INIT_FUNC_ARGS_PASSTHRU);
return SUCCESS;
}
|