Commit f21eff89 authored by Ondrej Sury's avatar Ondrej Sury

Imported Upstream version 5.5.0~beta1

parent 92984f18
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
21 Mar 2013, PHP 5.5.0 Beta 1
- Core:
. Added Zend Opcache extension and enable building it by default.
More details here: https://wiki.php.net/rfc/optimizerplus. (Dmitry)
. Added array_column function which returns a column in a multidimensional
array. https://wiki.php.net/rfc/array_column. (Ben Ramsey)
. Fixed bug #64354 (Unserialize array of objects whose class can't
be autoloaded fail). (Laruence)
. Added support for changing the process's title in CLI/CLI-Server SAPIs.
The implementation is more robust that the proctitle PECL module. More
details here: https://wiki.php.net/rfc/cli_process_title. (Keyur)
. Fixed bug #64370 (microtime(true) less than $_SERVER['REQUEST_TIME_FLOAT']).
(Anatol)
. Added support for non-scalar Iterator keys in foreach
(https://wiki.php.net/rfc/foreach-non-scalar-keys). (Nikita Popov)
- mysqlnd
. Fixed bug #63530 (mysqlnd_stmt::bind_one_parameter crashes, uses wrong alloc
for stmt->param_bind). (Andrey)
- DateTime
. Fixed bug #53437 (Crash when using unserialized DatePeriod instance).
(Gustavo, Derick, Anatol)
. Fixed bug #62852 (Unserialize Invalid Date causes crash). (Anatol)
- SPL:
. Implement FR #48358 (Add SplDoublyLinkedList::add() to insert an element
at a given offset). (Mark Baker, David Soria Parra)
- Zip:
. Bug #64452 (Zip crash intermittently). (Anatol)
07 Mar 2013, PHP 5.5.0 Alpha 6
- Core:
. Fixed bug #61025 (__invoke() visibility not honored). (Laruence)
. Fixed bug #49348 (Uninitialized ++$foo->bar; does not cause a notice).
(Stas)
......@@ -16,6 +50,10 @@ PHP NEWS
- DateTime:
. Fixed bug #64359 (strftime crash with VS2012). (Anatol)
- SNMP:
. Fixed bug #61981 (OO API, walk: $suffix_as_key is not working correctly).
(Boris Lytochkin)
21 Feb 2013, PHP 5.5.0 Alpha 5
- Core:
......
This diff is collapsed.
......@@ -154,7 +154,15 @@ origin <branch>``".
11. run: ``./makedist php 5.4.1``, this will export the tree, create configure
and build two tarballs (one gz and one bz2).
12. Commit those two tarballs to Git (php-distributions.git)
12. Commit those two tarballs to web/php-distributions.git, then update the git
submodule reference in web/php.git:
git submodule init;
git submodule update;
cd distributions;
git pull origin master;
cd ..;
git commit distributions;
git push;
13. Once the release has been tagged, contact the PHP Windows development team
(internals-win@lists.php.net) so that Windows binaries can be created. Once
......
......@@ -79,6 +79,10 @@ PHP 5.5 UPGRADE NOTES
(https://wiki.php.net/rfc/generators)
- ClassName::class syntax returning full class name for a class as
a string constant. (https://wiki.php.net/rfc/class_name_scalars)
- Support for changing the process's title in CLI/CLI-Server SAPIs. (Keyur)
(https://wiki.php.net/rfc/cli_process_title)
- Added support for non-scalar Iterator keys in foreach.
(https://wiki.php.net/rfc/foreach-non-scalar-keys).
========================================
2. Changes in SAPI modules
......
......@@ -64,6 +64,14 @@ void zend_qsort_r(void *base, size_t nmemb, size_t siz, compare_r_func_t compare
The extra argument it has (relatively to zend_qsort()) is passed to the
comparison function.
d. get_current_key
The signature of the get_current_key iteration handler has been changed to:
void (*get_current_key)(zend_object_iterator *iter, zval *key TSRMLS_DC);
The key should be written into the zval* using the ZVAL_* macros.
========================
2. Build system changes
========================
......
--TEST--
Bug #55156 (ReflectionClass::getDocComment() returns comment even though the class has none)
--INI--
opcache.save_comments=1
opcache.load_comments=1
--FILE--
<?php
......
--TEST--
Bug #61025 (__invoke() visibility not honored)
--FILE--
<?php
Interface InvokeAble {
static function __invoke();
}
class Bar {
private function __invoke() {
return __CLASS__;
}
}
$b = new Bar;
echo $b();
echo $b->__invoke();
?>
--EXPECTF--
Warning: The magic method __invoke() must have public visibility and cannot be static in %sbug61025.php on line %d
Warning: The magic method __invoke() must have public visibility and cannot be static in %sbug61025.php on line %d
Bar
Fatal error: Call to private method Bar::__invoke() from context '' in %sbug61025.php on line %d
--TEST--
Bug #62343 (Show class_alias In get_declared_classes())
--FILE--
<?php
class a { }
class_alias("a", "b");
$c = get_declared_classes();
var_dump(end($c));
var_dump(prev($c));
?>
--EXPECT--
string(1) "b"
string(1) "a"
--TEST--
Bug #63976 (Parent class incorrectly using child constant in class property)
--FILE--
<?php
if (1) {
class Foo {
const TABLE = "foo";
public $table = self::TABLE;
}
}
if (1) {
class Bar extends Foo {
const TABLE = "bar";
}
}
$bar = new Bar();
var_dump($bar->table);
?>
--EXPECT--
string(3) "foo"
--TEST--
Bug #64239 (get_class_methods() changed behavior)
--FILE--
<?php
class A {
public function test() { $this->backtrace(); }
}
class B {
use T2 { t2method as Bmethod; }
}
trait T2 {
public function t2method() {
}
}
var_dump(get_class_methods("B"));
--EXPECT--
array(2) {
[0]=>
string(7) "bmethod"
[1]=>
string(8) "t2method"
}
--TEST--
Bug #64354 (Unserialize array of objects whose class can't be autoloaded fail)
--FILE--
<?php
class B implements Serializable {
public function serialize() {
throw new Exception("serialize");
return NULL;
}
public function unserialize($data) {
}
}
$data = array(new B);
try {
serialize($data);
} catch (Exception $e) {
var_dump($e->getMessage());
}
?>
--EXPECTF--
string(9) "serialize"
--TEST--
Bug #64417 (BC break: ArrayAccess::&offsetGet() in a trait causes fatal error)
--FILE--
<?php
trait aa {
private $container = array();
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
public function offsetExists($offset) {
return isset($this->container[$offset]);
}
public function offsetUnset($offset) {
unset($this->container[$offset]);
}
public function &offsetGet($offset) {
$result = null;
if (isset($this->container[$offset])) {
$result = &$this->container[$offset];
}
return $result;
}
}
class obj implements ArrayAccess {
use aa;
}
$o = new obj;
$o['x'] = 1;
++$o['x'];
echo $o['x'], "\n";
--EXPECT--
2
......@@ -38,8 +38,6 @@ Stack trace:
#1 %s(%d): unserialize('O:9:"Generator"...')
#2 {main}
Notice: unserialize(): Error at offset 19 of 20 bytes in %s on line %d
exception 'Exception' with message 'Unserialization of 'Generator' is not allowed' in %s:%d
Stack trace:
#0 %s(%d): unserialize('C:9:"Generator"...')
......
--TEST--
Generators can return non-scalar keys
--FILE--
<?php
function gen() {
yield [1, 2, 3] => [4, 5, 6];
yield (object) ['a' => 'b'] => (object) ['b' => 'a'];
yield 3.14 => 2.73;
yield false => true;
yield true => false;
yield null => null;
}
foreach (gen() as $k => $v) {
var_dump($k, $v);
}
?>
--EXPECT--
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
array(3) {
[0]=>
int(4)
[1]=>
int(5)
[2]=>
int(6)
}
object(stdClass)#3 (1) {
["a"]=>
string(1) "b"
}
object(stdClass)#4 (1) {
["b"]=>
string(1) "a"
}
float(3.14)
float(2.73)
bool(false)
bool(true)
bool(true)
bool(false)
NULL
NULL
--TEST--
026: Name ambiguity (class name & namespace name)
--INI--
opcache.optimization_level=0
--FILE--
<?php
namespace Foo;
......
......@@ -299,7 +299,6 @@ void zend_error_noreturn(int type, const char *format, ...) __attribute__ ((nore
/*
* zval
*/
typedef struct _zval_struct zval;
typedef struct _zend_class_entry zend_class_entry;
typedef struct _zend_guard {
......@@ -365,6 +364,10 @@ struct _zval_struct {
#define Z_UNSET_ISREF(z) Z_UNSET_ISREF_P(&(z))
#define Z_SET_ISREF_TO(z, isref) Z_SET_ISREF_TO_P(&(z), isref)
#if ZEND_DEBUG
#define zend_always_inline inline
#define zend_never_inline
#else
#if defined(__GNUC__)
#if __GNUC__ >= 3
#define zend_always_inline inline __attribute__((always_inline))
......@@ -373,7 +376,6 @@ struct _zval_struct {
#define zend_always_inline inline
#define zend_never_inline
#endif
#elif defined(_MSC_VER)
#define zend_always_inline __forceinline
#define zend_never_inline
......@@ -381,6 +383,7 @@ struct _zval_struct {
#define zend_always_inline inline
#define zend_never_inline
#endif
#endif /* ZEND_DEBUG */
#if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX)
# define EXPECTED(condition) __builtin_expect(condition, 1)
......
......@@ -1051,6 +1051,41 @@ ZEND_API void zend_merge_properties(zval *obj, HashTable *properties, int destro
}
/* }}} */
static int zval_update_class_constant(zval **pp, int is_static, int offset TSRMLS_DC) /* {{{ */
{
if ((Z_TYPE_PP(pp) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT ||
(Z_TYPE_PP(pp) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT_ARRAY) {
zend_class_entry **scope = EG(in_execution)?&EG(scope):&CG(active_class_entry);
if ((*scope)->parent) {
zend_class_entry *ce = *scope;
HashPosition pos;
zend_property_info *prop_info;
do {
for (zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop_info, &pos) == SUCCESS;
zend_hash_move_forward_ex(&ce->properties_info, &pos)) {
if (is_static == ((prop_info->flags & ZEND_ACC_STATIC) != 0) &&
offset == prop_info->offset) {
int ret;
zend_class_entry *old_scope = *scope;
*scope = prop_info->ce;
ret = zval_update_constant(pp, (void*)1 TSRMLS_CC);
*scope = old_scope;
return ret;
}
}
ce = ce->parent;
} while (ce);
}
return zval_update_constant(pp, (void*)1 TSRMLS_CC);
}
return 0;
}
/* }}} */
ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
{
if ((class_type->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) == 0 || (!CE_STATIC_MEMBERS(class_type) && class_type->default_static_members_count)) {
......@@ -1063,7 +1098,7 @@ ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC
for (i = 0; i < class_type->default_properties_count; i++) {
if (class_type->default_properties_table[i]) {
zval_update_constant(&class_type->default_properties_table[i], (void**)1 TSRMLS_CC);
zval_update_class_constant(&class_type->default_properties_table[i], 0, i TSRMLS_CC);
}
}
......@@ -1104,7 +1139,7 @@ ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC
}
for (i = 0; i < class_type->default_static_members_count; i++) {
zval_update_constant(&CE_STATIC_MEMBERS(class_type)[i], (void**)1 TSRMLS_CC);
zval_update_class_constant(&CE_STATIC_MEMBERS(class_type)[i], 1, i TSRMLS_CC);
}
*scope = old_scope;
......@@ -1502,6 +1537,40 @@ ZEND_API int add_get_index_stringl(zval *arg, ulong index, const char *str, uint
}
/* }}} */
ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */
{
int result;
switch (Z_TYPE_P(key)) {
case IS_STRING:
result = zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof(zval *), NULL);
break;
case IS_NULL:
result = zend_symtable_update(ht, "", 1, &value, sizeof(zval *), NULL);
break;
case IS_RESOURCE:
zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(key), Z_LVAL_P(key));
/* break missing intentionally */
case IS_BOOL:
case IS_LONG:
result = zend_hash_index_update(ht, Z_LVAL_P(key), &value, sizeof(zval *), NULL);
break;
case IS_DOUBLE:
result = zend_hash_index_update(ht, zend_dval_to_lval(Z_DVAL_P(key)), &value, sizeof(zval *), NULL);
break;
default:
zend_error(E_WARNING, "Illegal offset type");
result = FAILURE;
}
if (result == SUCCESS) {
Z_ADDREF_P(value);
}
return result;
}
/* }}} */
ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, long n TSRMLS_DC) /* {{{ */
{
zval *tmp;
......
......@@ -426,6 +426,8 @@ ZEND_API int add_get_index_double(zval *arg, ulong idx, double d, void **dest);
ZEND_API int add_get_index_string(zval *arg, ulong idx, const char *str, void **dest, int duplicate);
ZEND_API int add_get_index_stringl(zval *arg, ulong idx, const char *str, uint length, void **dest, int duplicate);
ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value);
ZEND_API int add_property_long_ex(zval *arg, const char *key, uint key_len, long l TSRMLS_DC);
ZEND_API int add_property_null_ex(zval *arg, const char *key, uint key_len TSRMLS_DC);
ZEND_API int add_property_bool_ex(zval *arg, const char *key, uint key_len, int b TSRMLS_DC);
......
......@@ -1025,6 +1025,13 @@ ZEND_FUNCTION(get_object_vars)
}
/* }}} */
static int same_name(const char *key, const char *name, zend_uint name_len)
{
char *lcname = zend_str_tolower_dup(name, name_len);
int ret = memcmp(lcname, key, name_len) == 0;
efree(lcname);
return ret;
}
/* {{{ proto array get_class_methods(mixed class)
Returns an array of method names for class or class instance. */
......@@ -1072,14 +1079,26 @@ ZEND_FUNCTION(get_class_methods)
uint len = strlen(mptr->common.function_name);
/* Do not display old-style inherited constructors */
if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0 ||
mptr->common.scope == ce ||
zend_hash_get_current_key_ex(&ce->function_table, &key, &key_len, &num_index, 0, &pos) != HASH_KEY_IS_STRING ||
zend_binary_strcasecmp(key, key_len-1, mptr->common.function_name, len) == 0) {
if (zend_hash_get_current_key_ex(&ce->function_table, &key, &key_len, &num_index, 0, &pos) != HASH_KEY_IS_STRING) {
MAKE_STD_ZVAL(method_name);
ZVAL_STRINGL(method_name, mptr->common.function_name, len, 1);
zend_hash_next_index_insert(return_value->value.ht, &method_name, sizeof(zval *), NULL);
} else if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0 ||
mptr->common.scope == ce ||
zend_binary_strcasecmp(key, key_len-1, mptr->common.function_name, len) == 0) {
if (mptr->type == ZEND_USER_FUNCTION &&
*mptr->op_array.refcount > 1 &&
(len != key_len - 1 ||
!same_name(key, mptr->common.function_name, len))) {
MAKE_STD_ZVAL(method_name);
ZVAL_STRINGL(method_name, key, key_len - 1, 1);
zend_hash_next_index_insert(return_value->value.ht, &method_name, sizeof(zval *), NULL);
} else {
MAKE_STD_ZVAL(method_name);
ZVAL_STRINGL(method_name, mptr->common.function_name, len, 1);
zend_hash_next_index_insert(return_value->value.ht, &method_name, sizeof(zval *), NULL);
}
}
}
zend_hash_move_forward_ex(&ce->function_table, &pos);
......@@ -1625,7 +1644,6 @@ ZEND_FUNCTION(restore_exception_handler)
}
/* }}} */
static int copy_class_or_interface_name(zend_class_entry **pce TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
{
zval *array = va_arg(args, zval *);
......@@ -1636,7 +1654,13 @@ static int copy_class_or_interface_name(zend_class_entry **pce TSRMLS_DC, int nu
if ((hash_key->nKeyLength==0 || hash_key->arKey[0]!=0)
&& (comply_mask == (ce->ce_flags & mask))) {
add_next_index_stringl(array, ce->name, ce->name_length, 1);
if (ce->refcount > 1 &&
(ce->name_length != hash_key->nKeyLength - 1 ||
!same_name(hash_key->arKey, ce->name, ce->name_length))) {
add_next_index_stringl(array, hash_key->arKey, hash_key->nKeyLength - 1, 1);
} else {
add_next_index_stringl(array, ce->name, ce->name_length, 1);
}
}
return ZEND_HASH_APPLY_KEEP;
}
......
......@@ -291,7 +291,6 @@ static zend_object_value zend_closure_clone(zval *zobject TSRMLS_DC) /* {{{ */
}
/* }}} */
int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) /* {{{ */
{
zend_closure *closure;
......
......@@ -24,8 +24,6 @@
BEGIN_EXTERN_C()
#define ZEND_INVOKE_FUNC_NAME "__invoke"
void zend_register_closure_ce(TSRMLS_D);
extern ZEND_API zend_class_entry *zend_ce_closure;
......
......@@ -1621,6 +1621,10 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
}
} else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) {
if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
}
}
} else {
char *class_lcname;
......@@ -1677,6 +1681,10 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
}
CG(active_class_entry)->__tostring = (zend_function *) CG(active_op_array);
} else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) {
if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
}
} else if (!(fn_flags & ZEND_ACC_STATIC)) {
CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC;
}
......@@ -3823,7 +3831,7 @@ static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_
zend_uint other_flags = other_fn->common.scope->ce_flags;
return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
&& zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC)
&& ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC))
&& ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
(other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
}
......
......@@ -856,6 +856,7 @@ END_EXTERN_C()
#define ZEND_CALLSTATIC_FUNC_NAME "__callstatic"
#define ZEND_TOSTRING_FUNC_NAME "__tostring"
#define ZEND_AUTOLOAD_FUNC_NAME "__autoload"
#define ZEND_INVOKE_FUNC_NAME "__invoke"
/* The following constants may be combined in CG(compiler_options)
* to change the default compiler behavior */
......
......@@ -755,31 +755,17 @@ static void zend_generator_iterator_get_data(zend_object_iterator *iterator, zva
}
/* }}} */
static int zend_generator_iterator_get_key(zend_object_iterator *iterator, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
static void zend_generator_iterator_get_key(zend_object_iterator *iterator, zval *key TSRMLS_DC) /* {{{ */
{
zend_generator *generator = (zend_generator *) iterator->data;
zend_generator_ensure_initialized(generator TSRMLS_CC);
if (!generator->key) {
return HASH_KEY_NON_EXISTANT;
}
if (Z_TYPE_P(generator->key) == IS_LONG) {
*int_key = Z_LVAL_P(generator->key);
return HASH_KEY_IS_LONG;
}
if (Z_TYPE_P(generator->key) == IS_STRING) {
*str_key = estrndup(Z_STRVAL_P(generator->key), Z_STRLEN_P(generator->key));
*str_key_len = Z_STRLEN_P(generator->key) + 1;
return HASH_KEY_IS_STRING;
if (generator->key) {
ZVAL_ZVAL(key, generator->key, 1, 0);
} else {
ZVAL_NULL(key);
}
/* Waiting for Etienne's patch to allow arbitrary zval keys. Until then
* error out on non-int and non-string keys. */
zend_error_noreturn(E_ERROR, "Currently only int and string keys can be yielded");
return HASH_KEY_NON_EXISTANT; /* Nerver reached */
}
/* }}} */
......
......@@ -1171,6 +1171,24 @@ ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, char **str_index,
return HASH_KEY_NON_EXISTANT;
}
ZEND_API void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos) {
Bucket *p;
IS_CONSISTENT(ht);
p = pos ? (*pos) : ht->pInternalPointer;
if (!p) {
Z_TYPE_P(key) = IS_NULL;
} else if (p->nKeyLength) {
Z_TYPE_P(key) = IS_STRING;
Z_STRVAL_P(key) = IS_INTERNED(p->arKey) ? (char *) p->arKey : estrndup(p->arKey, p->nKeyLength - 1);
Z_STRLEN_P(key) = p->nKeyLength - 1;
} else {