Commit: 2bfb523f45cc0c64b5b63f9ad7fb6ec7c701d695
Author: Dmitry Stogov <dmi...@zend.com> Thu, 18 Apr 2013 10:48:16
+0400
Parents: 36d343c0c44da754957cfcb9b9544acdf0a9e229
Branches: master
Link:
http://git.php.net/?p=php-src.git;a=commitdiff;h=2bfb523f45cc0c64b5b63f9ad7fb6ec7c701d695
Log:
Merge identical constants (and related cache_slots) in op_array->literals table.
Changed paths:
A ext/opcache/Optimizer/compact_literals.c
M ext/opcache/Optimizer/zend_optimizer.c
M ext/opcache/Optimizer/zend_optimizer.h
A ext/opcache/tests/compact_literals.phpt
diff --git a/ext/opcache/Optimizer/compact_literals.c
b/ext/opcache/Optimizer/compact_literals.c
new file mode 100644
index 0000000..b292413
--- /dev/null
+++ b/ext/opcache/Optimizer/compact_literals.c
@@ -0,0 +1,481 @@
+/* pass 11
+ * - compact literals table
+ */
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+
+#define DEBUG_COMPACT_LITERALS 0
+
+#define LITERAL_VALUE 0x0100
+#define LITERAL_FUNC 0x0200
+#define LITERAL_CLASS 0x0300
+#define LITERAL_CONST 0x0400
+#define LITERAL_CLASS_CONST 0x0500
+#define LITERAL_STATIC_METHOD 0x0600
+#define LITERAL_STATIC_PROPERTY 0x0700
+#define LITERAL_METHOD 0x0800
+#define LITERAL_PROPERTY 0x0900
+
+#define LITERAL_EX_CLASS 0x4000
+#define LITERAL_EX_OBJ 0x2000
+#define LITERAL_MAY_MERGE 0x1000
+#define LITERAL_KIND_MASK 0x0f00
+#define LITERAL_NUM_RELATED_MASK 0x000f
+#define LITERAL_NUM_SLOTS_MASK 0x00f0
+#define LITERAL_NUM_SLOTS_SHIFT 4
+
+#define LITERAL_NUM_RELATED(info) (info & LITERAL_NUM_RELATED_MASK)
+#define LITERAL_NUM_SLOTS(info) ((info & LITERAL_NUM_SLOTS_MASK) >>
LITERAL_NUM_SLOTS_SHIFT)
+
+typedef struct _literal_info {
+ zend_uint flags; /* bitmask (see defines above) */
+ union {
+ int num; /* variable number or class name literal number */
+ } u;
+} literal_info;
+
+#define LITERAL_FLAGS(kind, slots, related) \
+ ((kind) | ((slots) << LITERAL_NUM_SLOTS_SHIFT) | (related))
+
+#define LITERAL_INFO(n, kind, merge, slots, related) do { \
+ info[n].flags = (((merge) ? LITERAL_MAY_MERGE : 0) |
LITERAL_FLAGS(kind, slots, related)); \
+ } while (0)
+
+#define LITERAL_INFO_CLASS(n, kind, merge, slots, related, _num) do { \
+ info[n].flags = (LITERAL_EX_CLASS | ((merge) ?
LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \
+ info[n].u.num = (_num); \
+ } while (0)
+
+#define LITERAL_INFO_OBJ(n, kind, merge, slots, related, _num) do { \
+ info[n].flags = (LITERAL_EX_OBJ | ((merge) ? LITERAL_MAY_MERGE
: 0) | LITERAL_FLAGS(kind, slots, related)); \
+ info[n].u.num = (_num); \
+ } while (0)
+
+static void optimizer_literal_obj_info(literal_info *info,
+ zend_uchar op_type,
+ znode_op op,
+ int constant,
+ zend_uint kind,
+ zend_uint slots,
+ zend_uint related,
+ zend_op_array *op_array)
+{
+ /* For now we merge only $this object properties and methods.
+ * In general it's also possible to do it for any CV variable as well,
+ * but it would require complex dataflow and/or type analysis.
+ */
+ if (Z_TYPE(op_array->literals[constant].constant) == IS_STRING &&
+ op_type == IS_UNUSED) {
+ LITERAL_INFO_OBJ(constant, kind, 1, slots, related,
op_array->this_var);
+ } else {
+ LITERAL_INFO(constant, kind, 0, slots, related);
+ }
+}
+
+static void optimizer_literal_class_info(literal_info *info,
+ zend_uchar op_type,
+ znode_op op,
+ int constant,
+ zend_uint kind,
+ zend_uint slots,
+ zend_uint related,
+ zend_op_array *op_array)
+{
+ if (op_type == IS_CONST) {
+ LITERAL_INFO_CLASS(constant, kind, 1, slots, related,
op.constant);
+ } else {
+ LITERAL_INFO(constant, kind, 0, slots, related);
+ }
+}
+
+static void optimizer_compact_literals(zend_op_array *op_array TSRMLS_DC)
+{
+ zend_op *opline, *end;
+ int i, j, n, *pos, *map, cache_slots;
+ ulong h;
+ literal_info *info;
+ int l_null = -1;
+ int l_false = -1;
+ int l_true = -1;
+ HashTable hash;
+ char *key;
+ int key_len;
+
+ if (op_array->last_literal) {
+ info = (literal_info*)ecalloc(op_array->last_literal,
sizeof(literal_info));
+
+ /* Mark literals of specific types */
+ opline = op_array->opcodes;
+ end = opline + op_array->last;
+ while (opline < end) {
+ switch (opline->opcode) {
+ case ZEND_DO_FCALL:
+ LITERAL_INFO(opline->op1.constant,
LITERAL_FUNC, 1, 1, 1);
+ break;
+ case ZEND_INIT_FCALL_BY_NAME:
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+
LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 2);
+ }
+ break;
+ case ZEND_INIT_NS_FCALL_BY_NAME:
+ LITERAL_INFO(opline->op2.constant,
LITERAL_FUNC, 1, 1, 3);
+ break;
+ case ZEND_INIT_METHOD_CALL:
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+ optimizer_literal_obj_info(
+ info,
+ opline->op1_type,
+ opline->op1,
+ opline->op2.constant,
+ LITERAL_METHOD, 2, 2,
+ op_array);
+ }
+ break;
+ case ZEND_INIT_STATIC_METHOD_CALL:
+ if (ZEND_OP1_TYPE(opline) == IS_CONST) {
+
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
+ }
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+ optimizer_literal_class_info(
+ info,
+ opline->op1_type,
+ opline->op1,
+ opline->op2.constant,
+ LITERAL_STATIC_METHOD,
(ZEND_OP1_TYPE(opline) == IS_CONST) ? 1 : 2, 2,
+ op_array);
+ }
+ break;
+ case ZEND_CATCH:
+ LITERAL_INFO(opline->op1.constant,
LITERAL_CLASS, 1, 1, 2);
+ break;
+ case ZEND_FETCH_CONSTANT:
+ if (ZEND_OP1_TYPE(opline) == IS_UNUSED)
{
+ if ((opline->extended_value &
(IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) ==
(IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) {
+
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 5);
+ } else {
+
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 3);
+ }
+ } else {
+ if (ZEND_OP1_TYPE(opline) ==
IS_CONST) {
+
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
+ }
+ optimizer_literal_class_info(
+ info,
+ opline->op1_type,
+ opline->op1,
+ opline->op2.constant,
+ LITERAL_CLASS_CONST,
(ZEND_OP1_TYPE(opline) == IS_CONST) ? 1 : 2, 1,
+ op_array);
+ }
+ break;
+ case ZEND_FETCH_R:
+ case ZEND_FETCH_W:
+ case ZEND_FETCH_RW:
+ case ZEND_FETCH_IS:
+ case ZEND_FETCH_UNSET:
+ case ZEND_FETCH_FUNC_ARG:
+ case ZEND_UNSET_VAR:
+ case ZEND_ISSET_ISEMPTY_VAR:
+ if (ZEND_OP2_TYPE(opline) == IS_UNUSED)
{
+ if (ZEND_OP1_TYPE(opline) ==
IS_CONST) {
+
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1);
+ }
+ } else {
+ if (ZEND_OP2_TYPE(opline) ==
IS_CONST) {
+
LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2);
+ }
+ if (ZEND_OP1_TYPE(opline) ==
IS_CONST) {
+
optimizer_literal_class_info(
+ info,
+
opline->op2_type,
+ opline->op2,
+
opline->op1.constant,
+
LITERAL_STATIC_PROPERTY, 2, 1,
+ op_array);
+ }
+ }
+ break;
+ case ZEND_FETCH_CLASS:
+ case ZEND_ADD_INTERFACE:
+ case ZEND_ADD_TRAIT:
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+
LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2);
+ }
+ break;
+ case ZEND_ASSIGN_OBJ:
+ case ZEND_FETCH_OBJ_R:
+ case ZEND_FETCH_OBJ_W:
+ case ZEND_FETCH_OBJ_RW:
+ case ZEND_FETCH_OBJ_IS:
+ case ZEND_FETCH_OBJ_UNSET:
+ case ZEND_FETCH_OBJ_FUNC_ARG:
+ case ZEND_UNSET_OBJ:
+ case ZEND_PRE_INC_OBJ:
+ case ZEND_PRE_DEC_OBJ:
+ case ZEND_POST_INC_OBJ:
+ case ZEND_POST_DEC_OBJ:
+ case ZEND_ISSET_ISEMPTY_PROP_OBJ:
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+ optimizer_literal_obj_info(
+ info,
+ opline->op1_type,
+ opline->op1,
+ opline->op2.constant,
+ LITERAL_PROPERTY, 2, 1,
+ op_array);
+ }
+ break;
+ case ZEND_ASSIGN_ADD:
+ case ZEND_ASSIGN_SUB:
+ case ZEND_ASSIGN_MUL:
+ case ZEND_ASSIGN_DIV:
+ case ZEND_ASSIGN_MOD:
+ case ZEND_ASSIGN_SL:
+ case ZEND_ASSIGN_SR:
+ case ZEND_ASSIGN_CONCAT:
+ case ZEND_ASSIGN_BW_OR:
+ case ZEND_ASSIGN_BW_AND:
+ case ZEND_ASSIGN_BW_XOR:
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+ if (opline->extended_value ==
ZEND_ASSIGN_OBJ) {
+
optimizer_literal_obj_info(
+ info,
+
opline->op1_type,
+ opline->op1,
+
opline->op2.constant,
+
LITERAL_PROPERTY, 2, 1,
+ op_array);
+ } else {
+
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 1);
+ }
+ }
+ break;
+ default:
+ if (ZEND_OP1_TYPE(opline) == IS_CONST) {
+
LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1);
+ }
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+
LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 1);
+ }
+ break;
+ }
+ opline++;
+ }
+
+#if DEBUG_COMPACT_LITERALS
+ {
+ int i, use_copy;
+ fprintf(stderr, "File %s func %s\n", op_array->filename,
+ op_array->function_name?
op_array->function_name : "main");
+ fprintf(stderr, "Literlas table size %d\n",
op_array->last_literal);
+
+ for (i = 0; i < op_array->last_literal; i++) {
+ zval zv = op_array->literals[i].constant;
+
zend_make_printable_zval(&op_array->literals[i].constant, &zv, &use_copy);
+ fprintf(stderr, "Literal %d, val (%d):%s\n", i,
Z_STRLEN(zv), Z_STRVAL(zv));
+ if (use_copy) {
+ zval_dtor(&zv);
+ }
+ }
+ fflush(stderr);
+ }
+#endif
+
+ /* Merge equal constants */
+ j = 0; cache_slots = 0;
+ zend_hash_init(&hash, 16, NULL, NULL, 0);
+ map = (int*)ecalloc(op_array->last_literal, sizeof(int));
+ for (i = 0; i < op_array->last_literal; i++) {
+ if (!info[i].flags) {
+ /* unsed literal */
+ zval_dtor(&op_array->literals[i].constant);
+ continue;
+ }
+ switch (Z_TYPE(op_array->literals[i].constant)) {
+ case IS_NULL:
+ if (l_null < 0) {
+ l_null = j;
+ if (i != j) {
+ op_array->literals[j] =
op_array->literals[i];
+ info[j] = info[i];
+ }
+ j++;
+ }
+ map[i] = l_null;
+ break;
+ case IS_BOOL:
+ if
(Z_LVAL(op_array->literals[i].constant)) {
+ if (l_true < 0) {
+ l_true = j;
+ if (i != j) {
+
op_array->literals[j] = op_array->literals[i];
+ info[j] =
info[i];
+ }
+ j++;
+ }
+ map[i] = l_true;
+ } else {
+ if (l_false < 0) {
+ l_false = j;
+ if (i != j) {
+
op_array->literals[j] = op_array->literals[i];
+ info[j] =
info[i];
+ }
+ j++;
+ }
+ map[i] = l_false;
+ }
+ break;
+ case IS_LONG:
+ if (zend_hash_index_find(&hash,
Z_LVAL(op_array->literals[i].constant), (void**)&pos) == SUCCESS) {
+ map[i] = *pos;
+ } else {
+ map[i] = j;
+ zend_hash_index_update(&hash,
Z_LVAL(op_array->literals[i].constant), (void**)&j, sizeof(int), NULL);
+ if (i != j) {
+ op_array->literals[j] =
op_array->literals[i];
+ info[j] = info[i];
+ }
+ j++;
+ }
+ break;
+ case IS_DOUBLE:
+ if (zend_hash_find(&hash,
(char*)&Z_DVAL(op_array->literals[i].constant), sizeof(double), (void**)&pos)
== SUCCESS) {
+ map[i] = *pos;
+ } else {
+ map[i] = j;
+ zend_hash_add(&hash,
(char*)&Z_DVAL(op_array->literals[i].constant), sizeof(double), (void**)&j,
sizeof(int), NULL);
+ if (i != j) {
+ op_array->literals[j] =
op_array->literals[i];
+ info[j] = info[i];
+ }
+ j++;
+ }
+ break;
+ case IS_STRING:
+ case IS_CONSTANT:
+ if (info[i].flags & LITERAL_MAY_MERGE) {
+ if (info[i].flags &
LITERAL_EX_OBJ) {
+ key_len =
MAX_LENGTH_OF_LONG + sizeof("->") + Z_STRLEN(op_array->literals[i].constant);
+ key = emalloc(key_len);
+ key_len = snprintf(key,
key_len-1, "%d->%s", info[i].u.num, Z_STRVAL(op_array->literals[i].constant));
+ } else if (info[i].flags &
LITERAL_EX_CLASS) {
+ zval *class_name =
&op_array->literals[(info[i].u.num < i) ? map[info[i].u.num] :
info[i].u.num].constant;
+ key_len =
Z_STRLEN_P(class_name) + sizeof("::") +
Z_STRLEN(op_array->literals[i].constant);
+ key = emalloc(key_len);
+ memcpy(key,
Z_STRVAL_P(class_name), Z_STRLEN_P(class_name));
+ memcpy(key +
Z_STRLEN_P(class_name), "::", sizeof("::") - 1);
+ memcpy(key +
Z_STRLEN_P(class_name) + sizeof("::") - 1,
+
Z_STRVAL(op_array->literals[i].constant),
+
Z_STRLEN(op_array->literals[i].constant) + 1);
+ } else {
+ key =
Z_STRVAL(op_array->literals[i].constant);
+ key_len =
Z_STRLEN(op_array->literals[i].constant)+1;
+ }
+ h = zend_hash_func(key,
key_len);
+ h += info[i].flags;
+ }
+ if ((info[i].flags & LITERAL_MAY_MERGE)
&&
+ zend_hash_quick_find(&hash,
key, key_len, h, (void**)&pos) == SUCCESS &&
+
Z_TYPE(op_array->literals[i].constant) ==
Z_TYPE(op_array->literals[*pos].constant) &&
+ info[i].flags ==
info[*pos].flags) {
+
+ if (info[i].flags &
(LITERAL_EX_OBJ|LITERAL_EX_CLASS)) {
+ efree(key);
+ }
+ map[i] = *pos;
+
zval_dtor(&op_array->literals[i].constant);
+ n =
LITERAL_NUM_RELATED(info[i].flags);
+ while (n > 1) {
+ i++;
+
zval_dtor(&op_array->literals[i].constant);
+ n--;
+ }
+ } else {
+ map[i] = j;
+ if (info[i].flags &
LITERAL_MAY_MERGE) {
+
zend_hash_quick_add(&hash, key, key_len, h, (void**)&j, sizeof(int), NULL);
+ if (info[i].flags &
(LITERAL_EX_OBJ|LITERAL_EX_CLASS)) {
+ efree(key);
+ }
+ }
+ if (i != j) {
+ op_array->literals[j] =
op_array->literals[i];
+ info[j] = info[i];
+ }
+ if
(!op_array->literals[j].hash_value) {
+ if
(IS_INTERNED(Z_STRVAL(op_array->literals[j].constant))) {
+
op_array->literals[j].hash_value =
INTERNED_HASH(Z_STRVAL(op_array->literals[j].constant));
+ } else {
+
op_array->literals[j].hash_value =
zend_hash_func(Z_STRVAL(op_array->literals[j].constant),
Z_STRLEN(op_array->literals[j].constant)+1);
+ }
+ }
+ if
(LITERAL_NUM_SLOTS(info[i].flags)) {
+
op_array->literals[j].cache_slot = cache_slots;
+ cache_slots +=
LITERAL_NUM_SLOTS(info[i].flags);
+ }
+ j++;
+ n =
LITERAL_NUM_RELATED(info[i].flags);
+ while (n > 1) {
+ i++;
+ if (i != j)
op_array->literals[j] = op_array->literals[i];
+ if
(!op_array->literals[j].hash_value) {
+ if
(IS_INTERNED(Z_STRVAL(op_array->literals[j].constant))) {
+
op_array->literals[j].hash_value =
INTERNED_HASH(Z_STRVAL(op_array->literals[j].constant));
+ } else {
+
op_array->literals[j].hash_value =
zend_hash_func(Z_STRVAL(op_array->literals[j].constant),
Z_STRLEN(op_array->literals[j].constant)+1);
+ }
+ }
+ j++;
+ n--;
+ }
+ }
+ break;
+ default:
+ /* don't merge other types */
+ map[i] = j;
+ if (i != j) {
+ op_array->literals[j] =
op_array->literals[i];
+ info[j] = info[i];
+ }
+ j++;
+ break;
+ }
+ }
+ zend_hash_destroy(&hash);
+ op_array->last_literal = j;
+ op_array->last_cache_slot = cache_slots;
+
+ /* Update opcodes to use new literals table */
+ opline = op_array->opcodes;
+ end = opline + op_array->last;
+ while (opline < end) {
+ if (ZEND_OP1_TYPE(opline) == IS_CONST) {
+ opline->op1.constant =
map[opline->op1.constant];
+ }
+ if (ZEND_OP2_TYPE(opline) == IS_CONST) {
+ opline->op2.constant =
map[opline->op2.constant];
+ }
+ opline++;
+ }
+ efree(map);
+ efree(info);
+
+#if DEBUG_COMPACT_LITERALS
+ {
+ int i, use_copy;
+ fprintf(stderr, "Optimized literlas table size %d\n",
op_array->last_literal);
+
+ for (i = 0; i < op_array->last_literal; i++) {
+ zval zv = op_array->literals[i].constant;
+
zend_make_printable_zval(&op_array->literals[i].constant, &zv, &use_copy);
+ fprintf(stderr, "Literal %d, val (%d):%s\n", i,
Z_STRLEN(zv), Z_STRVAL(zv));
+ if (use_copy) {
+ zval_dtor(&zv);
+ }
+ }
+ fflush(stderr);
+ }
+#endif
+ }
+}
+#endif
diff --git a/ext/opcache/Optimizer/zend_optimizer.c
b/ext/opcache/Optimizer/zend_optimizer.c
index b2148e1..fc0066e 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -112,6 +112,7 @@ int zend_optimizer_add_literal(zend_op_array *op_array,
const zval *zv TSRMLS_DC
#include "Optimizer/nop_removal.c"
#include "Optimizer/block_pass.c"
#include "Optimizer/optimize_temp_vars_5.c"
+#include "Optimizer/compact_literals.c"
static void zend_optimize(zend_op_array *op_array,
zend_persistent_script *script,
@@ -150,7 +151,7 @@ static void zend_optimize(zend_op_array *op_array,
*/
#include "Optimizer/pass5.c"
- /* pass 9:
+ /* pass 9:
* - Optimize temp variables usage
*/
#include "Optimizer/pass9.c"
@@ -159,6 +160,15 @@ static void zend_optimize(zend_op_array
*op_array,
* - remove NOPs
*/
#include "Optimizer/pass10.c"
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ /* pass 11:
+ * - Compact literals table
+ */
+ if (ZEND_OPTIMIZER_PASS_11 & OPTIMIZATION_LEVEL) {
+ optimizer_compact_literals(op_array TSRMLS_CC);
+ }
+#endif
}
static void zend_accel_optimize(zend_op_array *op_array,
diff --git a/ext/opcache/Optimizer/zend_optimizer.h
b/ext/opcache/Optimizer/zend_optimizer.h
index 1775994..4be37ba 100644
--- a/ext/opcache/Optimizer/zend_optimizer.h
+++ b/ext/opcache/Optimizer/zend_optimizer.h
@@ -35,7 +35,7 @@
#define ZEND_OPTIMIZER_PASS_8 (1<<7)
#define ZEND_OPTIMIZER_PASS_9 (1<<8) /* TMP VAR usage
*/
#define ZEND_OPTIMIZER_PASS_10 (1<<9) /* NOP removal
*/
-#define ZEND_OPTIMIZER_PASS_11 (1<<10)
+#define ZEND_OPTIMIZER_PASS_11 (1<<10) /* Merge equal constants
*/
#define ZEND_OPTIMIZER_PASS_12 (1<<11)
#define ZEND_OPTIMIZER_PASS_13 (1<<12)
#define ZEND_OPTIMIZER_PASS_14 (1<<13)
diff --git a/ext/opcache/tests/compact_literals.phpt
b/ext/opcache/tests/compact_literals.phpt
new file mode 100644
index 0000000..a691b91
--- /dev/null
+++ b/ext/opcache/tests/compact_literals.phpt
@@ -0,0 +1,215 @@
+--TEST--
+Test with compact literals
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+
+echo "array key hash" . ":" . PHP_EOL;
+$array = array(
+ "1" => "one",
+ "2" => "two",
+ "one" => 1,
+ "two" => 2,
+);
+
+unset($array["one"]);
+unset($array["2"]);
+
+print_r($array);
+
+echo "funcion define" . ":" . PHP_EOL;
+if (!function_exists("dummy")) {
+ function dummy() {
+ var_dump(__FUNCTION__);
+ }
+}
+
+dummy();
+
+$dummy = function () { var_dump("lambda" . "dummy"); };
+$dummy();
+
+if (!class_exists("A")) {
+ class A {
+ public static $name = "A";
+ public static function say($n = "name") {
+ var_dump(static::$name);
+ }
+ }
+}
+
+class B extends A {
+ public static $name = "B";
+}
+
+if (!class_exists("C")) {
+ class C extends B {
+ public static $name = "C";
+ }
+}
+
+A::say();
+B::Say();
+A::say();
+B::say();
+C::say();
+
+function get_eol_define() {
+ define("MY_EOL", PHP_EOL);
+}
+get_eol_define();
+define("EOL", MY_EOL);
+
+echo "constants define" . ":" . EOL;
+
+echo "define " . "TEST" . EOL;
+define("TEST", "TEST");
+
+class E {
+ public static $E="EP";
+ const E="E";
+ const TEST="NULL";
+}
+
+class F {
+ const F="F";
+ public static $E="FEP";
+ const E="FE";
+ const TEST="FALSE";
+ public static $F = "FP";
+}
+
+var_dump(TEST); //"TEST"
+var_dump(E::E); //"E"
+var_dump(F::E); //"FE"
+var_dump(F::F); //"F"
+var_dump(E::TEST); //"NULL"
+var_dump(F::TEST); //"FALSE"
+var_dump(E::$E); //"EP"
+var_dumP(F::$F); //"FP"
+var_dumP(F::$E); //"FEP"
+
+echo "propertes and methods" . EOL;
+
+class CH {
+ const H = "H";
+ public function h() {
+ var_dump(self::H);
+ }
+}
+
+class CI {
+ const H = "I";
+ public function h() {
+ var_dump(self::H);
+ }
+}
+
+function change(&$obj) {
+ $obj = new CH;
+}
+
+function geti() {
+ return new CI;
+}
+
+$h = new CH;
+
+echo "-->H" . PHP_EOL;
+$h->H();
+var_dump($h::H);
+var_dump(CH::H);
+
+$h->H();
+var_dump($h::H);
+var_dump(CH::H);
+
+echo "-->I" . PHP_EOL;
+$h = new CI;
+$h->H();
+var_dump($h::H);
+var_dump(CI::H);
+$h->H();
+var_dump($h::H);
+var_dump(CI::H);
+
+echo "-->H" . PHP_EOL;
+change($h);
+
+$h->H();
+var_dump($h::H);
+var_dump(CH::H);
+
+$h->H();
+var_dump($h::H);
+var_dump(CH::H);
+
+echo "-->I" . PHP_EOL;
+$h = geti();
+$h->H();
+var_dump($h::H);
+var_dump(CI::H);
+$h->H();
+var_dump($h::H);
+var_dump(CI::H);
+?>
+--EXPECT--
+array key hash:
+Array
+(
+ [1] => one
+ [two] => 2
+)
+funcion define:
+string(5) "dummy"
+string(11) "lambdadummy"
+string(1) "A"
+string(1) "B"
+string(1) "A"
+string(1) "B"
+string(1) "C"
+constants define:
+define TEST
+string(4) "TEST"
+string(1) "E"
+string(2) "FE"
+string(1) "F"
+string(4) "NULL"
+string(5) "FALSE"
+string(2) "EP"
+string(2) "FP"
+string(3) "FEP"
+propertes and methods
+-->H
+string(1) "H"
+string(1) "H"
+string(1) "H"
+string(1) "H"
+string(1) "H"
+string(1) "H"
+-->I
+string(1) "I"
+string(1) "I"
+string(1) "I"
+string(1) "I"
+string(1) "I"
+string(1) "I"
+-->H
+string(1) "H"
+string(1) "H"
+string(1) "H"
+string(1) "H"
+string(1) "H"
+string(1) "H"
+-->I
+string(1) "I"
+string(1) "I"
+string(1) "I"
+string(1) "I"
+string(1) "I"
+string(1) "I"
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php