Advertisement
Guest User

Untitled

a guest
Dec 21st, 2012
230
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 47.27 KB | None | 0 0
  1. diff --git a/Zend/tests/traits/bug60153.phpt b/Zend/tests/traits/bug60153.phpt
  2. index 8f01e72..979eced 100644
  3. --- a/Zend/tests/traits/bug60153.phpt
  4. +++ b/Zend/tests/traits/bug60153.phpt
  5. @@ -16,4 +16,4 @@ class C implements IFoo {
  6.  }
  7.  
  8.  --EXPECTF--
  9. -Fatal error: Declaration of C::oneArgument() must be compatible with IFoo::oneArgument($a) in %s on line %d
  10. +Fatal error: Declaration of TFoo::oneArgument() must be compatible with IFoo::oneArgument($a) in %s on line %d
  11. diff --git a/Zend/tests/traits/bug60217b.phpt b/Zend/tests/traits/bug60217b.phpt
  12. index f039550..eb852a4 100644
  13. --- a/Zend/tests/traits/bug60217b.phpt
  14. +++ b/Zend/tests/traits/bug60217b.phpt
  15. @@ -23,4 +23,4 @@ $o = new CBroken;
  16.  $o->foo(1);
  17.  
  18.  --EXPECTF--
  19. -Fatal error: Declaration of TBroken1::foo($a) must be compatible with TBroken2::foo($a, $b = 0) in %s on line %d
  20. +Fatal error: Declaration of TBroken2::foo($a, $b = 0) must be compatible with TBroken1::foo($a) in %s on line %d
  21. diff --git a/Zend/tests/traits/bug60217c.phpt b/Zend/tests/traits/bug60217c.phpt
  22. index ce89807..baa4314 100644
  23. --- a/Zend/tests/traits/bug60217c.phpt
  24. +++ b/Zend/tests/traits/bug60217c.phpt
  25. @@ -23,4 +23,4 @@ $o = new CBroken;
  26.  $o->foo(1);
  27.  
  28.  --EXPECTF--
  29. -Fatal error: Declaration of TBroken1::foo($a, $b = 0) must be compatible with TBroken2::foo($a) in %s on line %d
  30. +Fatal error: Declaration of TBroken2::foo($a) must be compatible with TBroken1::foo($a, $b = 0) in %s on line %d
  31. diff --git a/Zend/tests/traits/bugs/abstract-methods05.phpt b/Zend/tests/traits/bugs/abstract-methods05.phpt
  32. index e90ce39..9a1315f 100644
  33. --- a/Zend/tests/traits/bugs/abstract-methods05.phpt
  34. +++ b/Zend/tests/traits/bugs/abstract-methods05.phpt
  35. @@ -22,4 +22,4 @@ class TraitsTest1 {
  36.  
  37.  ?>
  38.  --EXPECTF--   
  39. -Fatal error: Declaration of THelloB::hello() must be compatible with THelloA::hello($a) in %s on line %d
  40. \ No newline at end of file
  41. +Fatal error: Declaration of THelloA::hello($a) must be compatible with THelloB::hello() in %s on line %d
  42. diff --git a/Zend/tests/traits/bugs/abstract-methods06.phpt b/Zend/tests/traits/bugs/abstract-methods06.phpt
  43. index 28ed672..8569aef 100644
  44. --- a/Zend/tests/traits/bugs/abstract-methods06.phpt
  45. +++ b/Zend/tests/traits/bugs/abstract-methods06.phpt
  46. @@ -23,4 +23,4 @@ class TraitsTest1 {
  47.  
  48.  ?>
  49.  --EXPECTF--   
  50. -Fatal error: Declaration of THelloA::hello($a) must be compatible with THelloB::hello() in %s on line %d
  51. \ No newline at end of file
  52. +Fatal error: Declaration of THelloB::hello() must be compatible with THelloA::hello($a) in %s on line %d
  53. diff --git a/Zend/tests/traits/error_010.phpt b/Zend/tests/traits/error_010.phpt
  54. index 8f3f7dd..de3741e 100644
  55. --- a/Zend/tests/traits/error_010.phpt
  56. +++ b/Zend/tests/traits/error_010.phpt
  57. @@ -10,13 +10,9 @@ trait c {
  58.     public function test() { return 2; }
  59.  }
  60.  
  61. -trait b {
  62. -   public function test() { return 1; }
  63. -}
  64. -
  65.  class bar {
  66. -   use foo, c { c::test insteadof foo, b; }
  67. -   use foo, c { c::test insteadof foo, b; }
  68. +   use foo, c { c::test insteadof foo; }
  69. +   use foo, c { c::test insteadof foo; }
  70.  }
  71.  
  72.  $x = new bar;
  73. diff --git a/Zend/tests/traits/inheritance003.phpt b/Zend/tests/traits/inheritance003.phpt
  74. index a41c4e4..22ff6e2 100644
  75. --- a/Zend/tests/traits/inheritance003.phpt
  76. +++ b/Zend/tests/traits/inheritance003.phpt
  77. @@ -35,4 +35,4 @@ $o->sayHello(array());
  78.  --EXPECTF--   
  79.  World!
  80.  
  81. -Fatal error: Declaration of MyHelloWorld::sayHello() must be compatible with Base::sayHello(array $a) in %s on line %d
  82. +Fatal error: Declaration of SayWorld::sayHello(Base $d) must be compatible with Base::sayHello(array $a) in %s on line %d
  83. diff --git a/Zend/zend.h b/Zend/zend.h
  84. index 3226f8c..849ad52 100644
  85. --- a/Zend/zend.h
  86. +++ b/Zend/zend.h
  87. @@ -437,7 +437,7 @@ struct _zend_trait_precedence {
  88.    
  89.     zend_class_entry** exclude_from_classes;
  90.    
  91. -   union _zend_function* function;
  92. +   union _zend_function* function; /* FIXME: kept in 5.4 for BC, not used */
  93.  };
  94.  typedef struct _zend_trait_precedence zend_trait_precedence;
  95.  
  96. @@ -455,7 +455,7 @@ struct _zend_trait_alias {
  97.     */
  98.     zend_uint modifiers;
  99.    
  100. -   union _zend_function* function;
  101. +   union _zend_function* function; /* FIXME: kept in 5.4 for BC, not used */
  102.  };
  103.  typedef struct _zend_trait_alias zend_trait_alias;
  104.  
  105. diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
  106. index 917e0c1..1b0e72b 100644
  107. --- a/Zend/zend_compile.c
  108. +++ b/Zend/zend_compile.c
  109. @@ -3527,8 +3527,7 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent
  110.  
  111.     if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {
  112.         ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
  113. -   } else if (!(ce->ce_flags & ZEND_ACC_IMPLEMENT_INTERFACES)
  114. -               && !(ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS)) {
  115. +   } else if (!(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
  116.         /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
  117.         zend_verify_abstract_class(ce TSRMLS_CC);
  118.     }
  119. @@ -3625,7 +3624,6 @@ ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *tr
  120.             }
  121.         }
  122.         ce->traits[ce->num_traits++] = trait;
  123. -       trait->refcount++;
  124.     }
  125.  }
  126.  /* }}} */
  127. @@ -3637,92 +3635,8 @@ static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_
  128.    
  129.     return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
  130.         && zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC)
  131. -       && ((fn_flags & ZEND_ACC_FINAL) == (other_flags & ZEND_ACC_FINAL))   /* equal final qualifier */
  132. -       && ((fn_flags & ZEND_ACC_STATIC)== (other_flags & ZEND_ACC_STATIC)); /* equal static qualifier */
  133. -}
  134. -/* }}} */
  135. -
  136. -static int zend_traits_merge_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
  137. -{
  138. -   size_t current;
  139. -   size_t i;
  140. -   size_t count;
  141. -   HashTable* resulting_table;
  142. -   HashTable** function_tables;
  143. -   zend_class_entry *ce;
  144. -   size_t collision = 0;
  145. -   size_t abstract_solved = 0;
  146. -   zend_function* other_trait_fn;
  147. -
  148. -   current         = va_arg(args, size_t);  /* index of current trait */
  149. -   count           = va_arg(args, size_t);
  150. -   resulting_table = va_arg(args, HashTable*);
  151. -   function_tables = va_arg(args, HashTable**);
  152. -   ce              = va_arg(args, zend_class_entry*);
  153. -
  154. -   for (i = 0; i < count; i++) {
  155. -       if (i == current) {
  156. -           continue; /* just skip this, cause its the table this function is applied on */
  157. -       }
  158. -      
  159. -       if (zend_hash_quick_find(function_tables[i], hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **)&other_trait_fn) == SUCCESS) {
  160. -           /* if it is an abstract method, there is no collision */
  161. -           if (other_trait_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
  162. -               /* Make sure they are compatible */
  163. -               /* In case both are abstract, just check prototype, but need to do that in both directions */
  164. -               if (!zend_traits_method_compatibility_check(fn, other_trait_fn TSRMLS_CC)) {
  165. -                   zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
  166. -                                               zend_get_function_declaration(fn TSRMLS_CC),
  167. -                                               zend_get_function_declaration(other_trait_fn TSRMLS_CC));
  168. -               }
  169. -              
  170. -               /* we can savely free and remove it from other table */
  171. -               zend_function_dtor(other_trait_fn);
  172. -               zend_hash_quick_del(function_tables[i], hash_key->arKey, hash_key->nKeyLength, hash_key->h);
  173. -           } else {
  174. -               /* if it is not an abstract method, there is still no collision */
  175. -               /* if fn is an abstract method */
  176. -               if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
  177. -                   /* Make sure they are compatible.
  178. -                      Here, we already know other_trait_fn cannot be abstract, full check ok. */
  179. -                   if (!zend_traits_method_compatibility_check(fn, other_trait_fn TSRMLS_CC)) {
  180. -                       zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
  181. -                                                   zend_get_function_declaration(fn TSRMLS_CC),
  182. -                                                   zend_get_function_declaration(other_trait_fn TSRMLS_CC));
  183. -                   }
  184. -                  
  185. -                   /* just mark as solved, will be added if its own trait is processed */
  186. -                   abstract_solved = 1;
  187. -               } else {
  188. -                   /* but else, we have a collision of non-abstract methods */
  189. -                   collision++;
  190. -                   zend_function_dtor(other_trait_fn);
  191. -                   zend_hash_quick_del(function_tables[i], hash_key->arKey, hash_key->nKeyLength, hash_key->h);
  192. -               }
  193. -           }
  194. -       }
  195. -   }
  196. -
  197. -   if (collision) {
  198. -       zend_function* class_fn;
  199. -
  200. -       /* make sure method is not already overridden in class */
  201. -       if (zend_hash_quick_find(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **)&class_fn) == FAILURE
  202. -           || class_fn->common.scope != ce) {
  203. -           zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s", fn->common.function_name, ce->name);
  204. -       }
  205. -
  206. -       zend_function_dtor(fn);
  207. -   } else if (abstract_solved) {
  208. -       zend_function_dtor(fn);
  209. -   } else {
  210. -       /* Add it to result function table */
  211. -       if (zend_hash_quick_add(resulting_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, fn, sizeof(zend_function), NULL)==FAILURE) {
  212. -           zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because failure occurred during updating resulting trait method table", fn->common.function_name);
  213. -       }
  214. -   }
  215. -
  216. -   return ZEND_HASH_APPLY_REMOVE;
  217. +       && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
  218. +           (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
  219.  }
  220.  /* }}} */
  221.  
  222. @@ -3767,66 +3681,84 @@ static void zend_add_magic_methods(zend_class_entry* ce, const char* mname, uint
  223.  }
  224.  /* }}} */
  225.  
  226. -static int zend_traits_merge_functions_to_class(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
  227. +static void zend_add_trait_method(zend_class_entry *ce, const char *name, const char *arKey, uint nKeyLength, zend_function *fn, HashTable **overriden TSRMLS_DC) /* {{{ */
  228.  {
  229. -   zend_class_entry *ce = va_arg(args, zend_class_entry*);
  230. -   zend_function* existing_fn = NULL;
  231. -   zend_function fn_copy, *fn_copy_p;
  232. -   zend_function* prototype = NULL;  /* is used to determine the prototype according to the inheritance chain */
  233. -
  234. -   if (zend_hash_quick_find(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void**) &existing_fn) == FAILURE ||
  235. -       existing_fn->common.scope != ce) {
  236. -       /* not found or inherited from other class or interface */
  237. -       zend_function* parent_function;
  238. +   zend_function *existing_fn = NULL;
  239. +   ulong h = zend_hash_func(arKey, nKeyLength);
  240.  
  241. -       if (ce->parent && zend_hash_quick_find(&ce->parent->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void**) &parent_function) != FAILURE) {
  242. -           prototype = parent_function; /* ->common.fn_flags |= ZEND_ACC_ABSTRACT; */
  243. -          
  244. -           /* we got that method in the parent class, and are going to override it,
  245. -             except, if the trait is just asking to have an abstract method implemented. */
  246. -           if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
  247. -               /* then we clean up an skip this method */
  248. -               zend_function_dtor(fn);
  249. -               return ZEND_HASH_APPLY_REMOVE;
  250. +   if (zend_hash_quick_find(&ce->function_table, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) {
  251. +       if (existing_fn->common.scope == ce) {
  252. +           /* members from the current class override trait methods */
  253. +           /* use temporary *overriden HashTable to detect hidden conflict */
  254. +           if (*overriden) {
  255. +               if (zend_hash_quick_find(*overriden, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) {
  256. +                   if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
  257. +                       /* Make sure the trait method is compatible with previosly declared abstarct method */
  258. +                       if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
  259. +                           zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
  260. +                               zend_get_function_declaration(fn TSRMLS_CC),
  261. +                               zend_get_function_declaration(existing_fn TSRMLS_CC));
  262. +                       }
  263. +                   } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
  264. +                       /* Make sure the abstract declaration is compatible with previous declaration */
  265. +                       if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
  266. +                           zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
  267. +                               zend_get_function_declaration(fn TSRMLS_CC),
  268. +                               zend_get_function_declaration(existing_fn TSRMLS_CC));
  269. +                       }
  270. +                       return;
  271. +                   }
  272. +               }
  273. +           } else {
  274. +               ALLOC_HASHTABLE(*overriden);
  275. +               zend_hash_init_ex(*overriden, 2, NULL, NULL, 0, 0);
  276.             }
  277. -       }
  278. -
  279. -       fn->common.scope = ce;
  280. -       fn->common.prototype = prototype;
  281. -
  282. -       if (prototype
  283. -           && (prototype->common.fn_flags & ZEND_ACC_IMPLEMENTED_ABSTRACT
  284. -           || prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
  285. -           fn->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
  286. -       } else if (fn->common.fn_flags & ZEND_ACC_IMPLEMENTED_ABSTRACT) {
  287. -           /* remove ZEND_ACC_IMPLEMENTED_ABSTRACT flag, think it shouldn't be copied to class */
  288. -           fn->common.fn_flags = fn->common.fn_flags - ZEND_ACC_IMPLEMENTED_ABSTRACT;
  289. -       }
  290. -
  291. -       /* check whether the trait method fullfills the inheritance requirements */
  292. -       if (prototype) {
  293. -           do_inheritance_check_on_method(fn, prototype TSRMLS_CC);
  294. -       }
  295. -
  296. -       /* one more thing: make sure we properly implement an abstract method */
  297. -       if (existing_fn && existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
  298. -           prototype = fn->common.prototype;
  299. +           zend_hash_quick_update(*overriden, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn);
  300. +           return;
  301. +       } else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
  302. +           /* Make sure the trait method is compatible with previosly declared abstarct method */
  303. +           if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
  304. +               zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
  305. +                   zend_get_function_declaration(fn TSRMLS_CC),
  306. +                   zend_get_function_declaration(existing_fn TSRMLS_CC));
  307. +           }
  308. +       } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
  309. +           /* Make sure the abstract declaration is compatible with previous declaration */
  310. +           if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
  311. +               zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
  312. +                   zend_get_function_declaration(fn TSRMLS_CC),
  313. +                   zend_get_function_declaration(existing_fn TSRMLS_CC));
  314. +           }
  315. +           return;
  316. +       } else if ((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
  317. +           /* two trais can't define the same non-abstarct method */
  318. +#if 1
  319. +           zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s",
  320. +               name, ce->name);
  321. +#else      /* TODO: better errot message */
  322. +           zend_error(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
  323. +               fn->common.scope->name, fn->common.function_name,
  324. +               ce->name, name,
  325. +               existing_fn->common.scope->name, existing_fn->common.function_name);
  326. +#endif
  327. +       } else {
  328. +           /* inherited members are overridden by members inserted by traits */
  329. +           /* check whether the trait method fullfills the inheritance requirements */
  330.             do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC);
  331. -           fn->common.prototype = prototype;
  332.         }
  333. +   }
  334.  
  335. -       /* delete inherited fn if the function to be added is not abstract */
  336. -       if (existing_fn
  337. -           && existing_fn->common.scope != ce
  338. -           && (fn->common.fn_flags & ZEND_ACC_ABSTRACT) == 0) {
  339. -           /* it is just a reference which was added to the subclass while doing
  340. -              the inheritance, so we can deleted now, and will add the overriding
  341. -              method afterwards.
  342. -              Except, if we try to add an abstract function, then we should not
  343. -              delete the inherited one */
  344. -           zend_hash_quick_del(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h);
  345. -       }
  346. +   function_add_ref(fn);
  347. +   zend_hash_quick_update(&ce->function_table, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn);
  348. +   zend_add_magic_methods(ce, arKey, nKeyLength, fn TSRMLS_CC);
  349. +}
  350. +/* }}} */
  351.  
  352. +static int zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce TSRMLS_DC) /* {{{ */
  353. +{
  354. +   if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
  355. +
  356. +       fn->common.scope = ce;
  357.  
  358.         if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
  359.             ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
  360. @@ -3834,78 +3766,60 @@ static int zend_traits_merge_functions_to_class(zend_function *fn TSRMLS_DC, int
  361.         if (fn->op_array.static_variables) {
  362.             ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
  363.         }
  364. -       fn_copy = *fn;
  365. -       function_add_ref(&fn_copy);
  366. -
  367. -       if (zend_hash_quick_update(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, &fn_copy, sizeof(zend_function), (void**)&fn_copy_p)==FAILURE) {
  368. -           zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because failure occurred during updating class method table", hash_key->arKey);
  369. -       }
  370. -
  371. -       zend_add_magic_methods(ce, hash_key->arKey, hash_key->nKeyLength, fn_copy_p TSRMLS_CC);
  372. -
  373. -       zend_function_dtor(fn);
  374. -   } else {
  375. -       zend_function_dtor(fn);
  376.     }
  377. -
  378. -   return ZEND_HASH_APPLY_REMOVE;
  379. +   return ZEND_HASH_APPLY_KEEP;
  380.  }
  381.  /* }}} */
  382.  
  383.  static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
  384.  {
  385. -   HashTable* target;
  386. -   zend_trait_alias** aliases;
  387. -   HashTable* exclude_table;
  388. -   char* lcname;
  389. -   unsigned int fnname_len;
  390. -   zend_function fn_copy;
  391. -   void* dummy;
  392. -   size_t i = 0;
  393. -
  394. -   target        = va_arg(args, HashTable*);
  395. -   aliases       = va_arg(args, zend_trait_alias**);
  396. +   zend_class_entry  *ce;
  397. +   HashTable         **overriden;
  398. +   zend_trait_alias  *alias, **alias_ptr;
  399. +   HashTable         *exclude_table;
  400. +   char              *lcname;
  401. +   unsigned int       fnname_len;
  402. +   zend_function      fn_copy;
  403. +   void              *dummy;
  404. +
  405. +   ce            = va_arg(args, zend_class_entry*);
  406. +   overriden     = va_arg(args, HashTable**);
  407.     exclude_table = va_arg(args, HashTable*);
  408. -
  409. +  
  410.     fnname_len = strlen(fn->common.function_name);
  411.  
  412.     /* apply aliases which are qualified with a class name, there should not be any ambiguity */
  413. -   if (aliases) {
  414. -       while (aliases[i]) {
  415. +   if (ce->trait_aliases) {
  416. +       alias_ptr = ce->trait_aliases;
  417. +       alias = *alias_ptr;
  418. +       while (alias) {
  419.             /* Scope unset or equal to the function we compare to, and the alias applies to fn */
  420. -           if (aliases[i]->alias != NULL
  421. -               && (!aliases[i]->trait_method->ce || fn->common.scope == aliases[i]->trait_method->ce)
  422. -               && aliases[i]->trait_method->mname_len == fnname_len
  423. -               && (zend_binary_strcasecmp(aliases[i]->trait_method->method_name, aliases[i]->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) {
  424. +           if (alias->alias != NULL
  425. +               && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
  426. +               && alias->trait_method->mname_len == fnname_len
  427. +               && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) {
  428.                 fn_copy = *fn;
  429. -               function_add_ref(&fn_copy);
  430. -               /* this function_name is never destroyed, because ZEND_ACC_ALIAS
  431. -                  flag is set */
  432. -               fn_copy.common.function_name = aliases[i]->alias;
  433. -               fn_copy.common.fn_flags |= ZEND_ACC_ALIAS;
  434.                    
  435.                 /* if it is 0, no modifieres has been changed */
  436. -               if (aliases[i]->modifiers) {
  437. -                   fn_copy.common.fn_flags = aliases[i]->modifiers | ZEND_ACC_ALIAS;
  438. -                   if (!(aliases[i]->modifiers & ZEND_ACC_PPP_MASK)) {
  439. +               if (alias->modifiers) {
  440. +                   fn_copy.common.fn_flags = alias->modifiers;
  441. +                   if (!(alias->modifiers & ZEND_ACC_PPP_MASK)) {
  442.                         fn_copy.common.fn_flags |= ZEND_ACC_PUBLIC;
  443.                     }
  444.                     fn_copy.common.fn_flags |= fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK);
  445.                 }
  446.  
  447. -               lcname = zend_str_tolower_dup(aliases[i]->alias, aliases[i]->alias_len);
  448. -
  449. -               if (zend_hash_add(target, lcname, aliases[i]->alias_len+1, &fn_copy, sizeof(zend_function), NULL)==FAILURE) {
  450. -                   zend_error(E_COMPILE_ERROR, "Failed to add aliased trait method (%s) to the trait table. There is probably already a trait method with the same name", fn_copy.common.function_name);
  451. -               }
  452. +               lcname = zend_str_tolower_dup(alias->alias, alias->alias_len);
  453. +               zend_add_trait_method(ce, alias->alias, lcname, alias->alias_len+1, &fn_copy, overriden TSRMLS_DC);
  454.                 efree(lcname);
  455.  
  456. -               /** Record the trait from which this alias was resolved. */
  457. -               if (!aliases[i]->trait_method->ce) {
  458. -                   aliases[i]->trait_method->ce = fn->common.scope;
  459. +               /* Record the trait from which this alias was resolved. */
  460. +               if (!alias->trait_method->ce) {
  461. +                   alias->trait_method->ce = fn->common.scope;
  462.                 }
  463.             }
  464. -           i++;
  465. +           alias_ptr++;
  466. +           alias = *alias_ptr;
  467.         }
  468.     }
  469.  
  470. @@ -3914,38 +3828,35 @@ static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args,
  471.     if (exclude_table == NULL || zend_hash_find(exclude_table, lcname, fnname_len, &dummy) == FAILURE) {
  472.         /* is not in hashtable, thus, function is not to be excluded */
  473.         fn_copy = *fn;
  474. -       function_add_ref(&fn_copy);
  475. -       fn_copy.common.fn_flags |= ZEND_ACC_ALIAS;
  476. -
  477. -       /* apply aliases which are not qualified by a class name, or which have not
  478. -        * alias name, just setting visibility */
  479. -       if (aliases) {
  480. -           i = 0;
  481. -           while (aliases[i]) {
  482. +
  483. +       /* apply aliases which have not alias name, just setting visibility */
  484. +       if (ce->trait_aliases) {
  485. +           alias_ptr = ce->trait_aliases;
  486. +           alias = *alias_ptr;
  487. +           while (alias) {
  488.                 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
  489. -               if (aliases[i]->alias == NULL && aliases[i]->modifiers != 0
  490. -                   && (!aliases[i]->trait_method->ce || fn->common.scope == aliases[i]->trait_method->ce)
  491. -                   && (aliases[i]->trait_method->mname_len == fnname_len)
  492. -                   && (zend_binary_strcasecmp(aliases[i]->trait_method->method_name, aliases[i]->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) {
  493. -                   fn_copy.common.fn_flags = aliases[i]->modifiers | ZEND_ACC_ALIAS;
  494. +               if (alias->alias == NULL && alias->modifiers != 0
  495. +                   && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
  496. +                   && (alias->trait_method->mname_len == fnname_len)
  497. +                   && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) {
  498.  
  499. -                   if (!(aliases[i]->modifiers & ZEND_ACC_PPP_MASK)) {
  500. +                   fn_copy.common.fn_flags = alias->modifiers;
  501. +                   if (!(alias->modifiers & ZEND_ACC_PPP_MASK)) {
  502.                         fn_copy.common.fn_flags |= ZEND_ACC_PUBLIC;
  503.                     }
  504.                     fn_copy.common.fn_flags |= fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK);
  505.  
  506.                     /** Record the trait from which this alias was resolved. */
  507. -                   if (!aliases[i]->trait_method->ce) {
  508. -                       aliases[i]->trait_method->ce = fn->common.scope;
  509. +                   if (!alias->trait_method->ce) {
  510. +                       alias->trait_method->ce = fn->common.scope;
  511.                     }
  512.                 }
  513. -               i++;
  514. +               alias_ptr++;
  515. +               alias = *alias_ptr;
  516.             }
  517.         }
  518.  
  519. -       if (zend_hash_add(target, lcname, fnname_len+1, &fn_copy, sizeof(zend_function), NULL)==FAILURE) {
  520. -           zend_error(E_COMPILE_ERROR, "Failed to add trait method (%s) to the trait table. There is probably already a trait method with the same name", fn_copy.common.function_name);
  521. -       }
  522. +       zend_add_trait_method(ce, fn->common.function_name, lcname, fnname_len+1, &fn_copy, overriden TSRMLS_DC);
  523.     }
  524.  
  525.     efree(lcname);
  526. @@ -3954,10 +3865,16 @@ static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args,
  527.  }
  528.  /* }}} */
  529.  
  530. -/* Copies function table entries to target function table with applied aliasing */
  531. -static void zend_traits_copy_trait_function_table(HashTable *target, HashTable *source, zend_trait_alias** aliases, HashTable* exclude_table TSRMLS_DC) /* {{{ */
  532. +static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
  533.  {
  534. -   zend_hash_apply_with_arguments(source TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, target, aliases, exclude_table);
  535. +   zend_uint i;
  536. +
  537. +   for (i = 0; i < ce->num_traits; i++) {
  538. +       if (ce->traits[i] == trait) {
  539. +           return;
  540. +       }
  541. +   }
  542. +   zend_error(E_COMPILE_ERROR, "Trait %s is not used", trait->name);
  543.  }
  544.  /* }}} */
  545.  
  546. @@ -3980,6 +3897,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /*
  547.                                 ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
  548.                     zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name);
  549.                 }
  550. +               zend_check_trait_usage(ce, cur_precedence->trait_method->ce TSRMLS_CC);
  551.  
  552.                 /** Ensure that the prefered method is actually available. */
  553.                 lcname = zend_str_tolower_dup(cur_method_ref->method_name,
  554. @@ -4008,8 +3926,9 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /*
  555.  
  556.                     if (!(cur_precedence->exclude_from_classes[j] = zend_fetch_class(class_name, name_length, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
  557.                         zend_error(E_COMPILE_ERROR, "Could not find trait %s", class_name);
  558. -                   }
  559. -                  
  560. +                   }                  
  561. +                   zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j] TSRMLS_CC);
  562. +
  563.                     /* make sure that the trait method is not from a class mentioned in
  564.                      exclude_from_classes, for consistency */
  565.                     if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[i]) {
  566. @@ -4038,6 +3957,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /*
  567.                 if (!(cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, cur_method_ref->cname_len, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
  568.                     zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name);
  569.                 }
  570. +               zend_check_trait_usage(ce, cur_method_ref->ce TSRMLS_CC);
  571.  
  572.                 /** And, ensure that the referenced method is resolvable, too. */
  573.                 lcname = zend_str_tolower_dup(cur_method_ref->method_name,
  574. @@ -4087,122 +4007,49 @@ static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_tra
  575.  
  576.  static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
  577.  {
  578. -   HashTable** function_tables;
  579. -   HashTable* resulting_table;
  580. -   HashTable exclude_table;
  581. -   size_t i;
  582. +   zend_uint i;
  583. +   HashTable *overriden = NULL;
  584.  
  585. -   /* prepare copies of trait function tables for combination */
  586. -   function_tables = emalloc(sizeof(HashTable*) * ce->num_traits);
  587. -   resulting_table = (HashTable *)emalloc(sizeof(HashTable));
  588. -  
  589. -   /* TODO: revisit this start size, may be its not optimal */
  590. -   zend_hash_init_ex(resulting_table, 10, NULL, NULL, 0, 0);
  591. -  
  592.     for (i = 0; i < ce->num_traits; i++) {
  593. -       function_tables[i] = (HashTable *)emalloc(sizeof(HashTable));
  594. -       zend_hash_init_ex(function_tables[i], ce->traits[i]->function_table.nNumOfElements, NULL, NULL, 1, 0);
  595. -
  596.         if (ce->trait_precedences) {
  597. +           HashTable exclude_table;
  598. +
  599.             /* TODO: revisit this start size, may be its not optimal */
  600.             zend_hash_init_ex(&exclude_table, 2, NULL, NULL, 0, 0);
  601.  
  602.             zend_traits_compile_exclude_table(&exclude_table, ce->trait_precedences, ce->traits[i]);
  603.  
  604.             /* copies functions, applies defined aliasing, and excludes unused trait methods */
  605. -           zend_traits_copy_trait_function_table(function_tables[i], &ce->traits[i]->function_table, ce->trait_aliases, &exclude_table TSRMLS_CC);
  606. +           zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, &exclude_table);
  607. +
  608.             zend_hash_destroy(&exclude_table);
  609.         } else {
  610. -           zend_traits_copy_trait_function_table(function_tables[i], &ce->traits[i]->function_table, ce->trait_aliases, NULL TSRMLS_CC);
  611. +           zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, NULL);
  612.         }
  613.     }
  614.    
  615. -   /* now merge trait methods */
  616. -   for (i = 0; i < ce->num_traits; i++) {
  617. -       zend_hash_apply_with_arguments(function_tables[i] TSRMLS_CC, (apply_func_args_t)zend_traits_merge_functions, 5, i, ce->num_traits, resulting_table, function_tables, ce);
  618. -   }
  619. -  
  620. -   /* Now the resulting_table contains all trait methods we would have to
  621. -    * add to the class in the following step the methods are inserted into the method table
  622. -    * if there is already a method with the same name it is replaced iff ce != fn.scope
  623. -    * --> all inherited methods are overridden, methods defined in the class are left untouched
  624. -    */
  625. -   zend_hash_apply_with_arguments(resulting_table TSRMLS_CC, (apply_func_args_t)zend_traits_merge_functions_to_class, 1, ce);
  626. -  
  627. -   /* free temporary function tables */
  628. -   for (i = 0; i < ce->num_traits; i++) {
  629. -       /* zend_hash_destroy(function_tables[i]); */
  630. -       zend_hash_graceful_destroy(function_tables[i]);
  631. -       efree(function_tables[i]);
  632. -   }
  633. -   efree(function_tables);
  634. +    zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t)zend_fixup_trait_method, ce TSRMLS_CC);
  635.  
  636. -   /* free temporary resulting table */
  637. -   /* zend_hash_destroy(resulting_table); */
  638. -   zend_hash_graceful_destroy(resulting_table);
  639. -   efree(resulting_table);
  640. +   if (overriden) {
  641. +       zend_hash_destroy(overriden);
  642. +       FREE_HASHTABLE(overriden);
  643. +   }
  644.  }
  645.  /* }}} */
  646.  
  647.  static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, const char* prop_name, int prop_name_length, ulong prop_hash, zend_class_entry *coliding_ce) /* {{{ */
  648.  {
  649.     size_t i;
  650. -   zend_property_info *coliding_prop;
  651. -   for (i = 0; (i < current_trait) && (i < ce->num_traits); i++) {
  652. -       if (zend_hash_quick_find(&ce->traits[i]->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop) == SUCCESS) {
  653. -           return ce->traits[i];
  654. -       }
  655. -   }
  656. -
  657. -   return coliding_ce;
  658. -}
  659. -/* }}} */
  660. -
  661. -static void zend_traits_register_private_property(zend_class_entry *ce, const char *name, int name_len, zend_property_info *old_info, zval *property TSRMLS_DC) /* {{{ */
  662. -{
  663. -   char *priv_name;
  664. -   int priv_name_length;
  665. -   const char *interned_name;
  666. -   zend_property_info property_info;
  667. -   ulong h = zend_get_hash_value(name, name_len+1);
  668. -   property_info = *old_info;
  669.  
  670. -   if (old_info->flags & ZEND_ACC_STATIC) {
  671. -       property_info.offset = ce->default_static_members_count++;
  672. -       ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval*) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
  673. -       ce->default_static_members_table[property_info.offset] = property;
  674. -       if (ce->type == ZEND_USER_CLASS) {
  675. -           ce->static_members_table = ce->default_static_members_table;
  676. -       }
  677. -   } else {
  678. -       property_info.offset = ce->default_properties_count++;
  679. -       ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval*) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
  680. -       ce->default_properties_table[property_info.offset] = property;
  681. -   }
  682. -
  683. -   zend_mangle_property_name(&priv_name, &priv_name_length, ce->name, ce->name_length, name, name_len, ce->type & ZEND_INTERNAL_CLASS);
  684. -   property_info.name = priv_name;
  685. -   property_info.name_length = priv_name_length;
  686. -
  687. -   interned_name = zend_new_interned_string(property_info.name, property_info.name_length+1, 0 TSRMLS_CC);
  688. -   if (interned_name != property_info.name) {
  689. -       if (ce->type == ZEND_USER_CLASS) {
  690. -           efree((char*)property_info.name);
  691. -       } else {
  692. -           free((char*)property_info.name);
  693. +   if (coliding_ce == ce) {
  694. +       for (i = 0; i < current_trait; i++) {
  695. +           if (zend_hash_quick_exists(&ce->traits[i]->properties_info, prop_name, prop_name_length+1, prop_hash)) {
  696. +               return ce->traits[i];
  697. +           }
  698.         }
  699. -       property_info.name = interned_name;
  700.     }
  701.  
  702. -   property_info.h = zend_get_hash_value(property_info.name, property_info.name_length+1);
  703. -
  704. -   property_info.ce = ce;
  705. -
  706. -   if (property_info.doc_comment) {
  707. -       property_info.doc_comment = estrndup(property_info.doc_comment, property_info.doc_comment_len);
  708. -   }
  709. -
  710. -   zend_hash_quick_update(&ce->properties_info, name, name_len+1, h, &property_info, sizeof(zend_property_info), NULL);
  711. +   return coliding_ce;
  712.  }
  713.  /* }}} */
  714.  
  715. @@ -4219,7 +4066,8 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
  716.     zend_bool not_compatible;
  717.     zval* prop_value;
  718.     char* doc_comment;  
  719. -  
  720. +   zend_uint flags;
  721. +
  722.     /* In the following steps the properties are inserted into the property table
  723.      * for that, a very strict approach is applied:
  724.      * - check for compatibility, if not compatible with any property in class -> fatal
  725. @@ -4232,7 +4080,8 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
  726.             /* first get the unmangeld name if necessary,
  727.              * then check whether the property is already there
  728.              */
  729. -           if ((property_info->flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
  730. +           flags = property_info->flags;
  731. +           if ((flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
  732.                 prop_hash = property_info->h;
  733.                 prop_name = property_info->name;
  734.                 prop_name_length = property_info->name_length;
  735. @@ -4246,61 +4095,50 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
  736.  
  737.             /* next: check for conflicts with current class */
  738.             if (zend_hash_quick_find(&ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop) == SUCCESS) {
  739. -               if (coliding_prop->flags & ZEND_ACC_SHADOW) {
  740. -                   /* this one is inherited, lets look it up in its own class */
  741. -                   zend_hash_quick_find(&coliding_prop->ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop);
  742. -                   if (coliding_prop->flags & ZEND_ACC_PRIVATE) {
  743. -                       /* private property, make the property_info.offset indenpended */
  744. -                       if (property_info->flags & ZEND_ACC_STATIC) {
  745. -                           prop_value = ce->traits[i]->default_static_members_table[property_info->offset];
  746. +               if (coliding_prop->flags & ZEND_ACC_SHADOW) {                  
  747. +                   zend_hash_quick_del(&ce->properties_info, prop_name, prop_name_length+1, prop_hash);
  748. +                   flags |= ZEND_ACC_CHANGED;
  749. +               } else {               
  750. +                   if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
  751. +                       == (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
  752. +                       /* flags are identical, now the value needs to be checked */
  753. +                       if (flags & ZEND_ACC_STATIC) {
  754. +                           not_compatible = (FAILURE == compare_function(&compare_result,
  755. +                                             ce->default_static_members_table[coliding_prop->offset],
  756. +                                             ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC))
  757. +                                 || (Z_LVAL(compare_result) != 0);
  758.                         } else {
  759. -                           prop_value = ce->traits[i]->default_properties_table[property_info->offset];
  760. +                           not_compatible = (FAILURE == compare_function(&compare_result,
  761. +                                             ce->default_properties_table[coliding_prop->offset],
  762. +                                             ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC))
  763. +                                 || (Z_LVAL(compare_result) != 0);
  764.                         }
  765. -                       Z_ADDREF_P(prop_value);
  766. -
  767. -                       zend_traits_register_private_property(ce, prop_name, prop_name_length, property_info, prop_value TSRMLS_CC);
  768. -                       continue;
  769. -                   }
  770. -               }
  771. -              
  772. -               if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
  773. -                   == (property_info->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
  774. -                   /* flags are identical, now the value needs to be checked */
  775. -                   if (property_info->flags & ZEND_ACC_STATIC) {
  776. -                       not_compatible = (FAILURE == compare_function(&compare_result,
  777. -                                         ce->default_static_members_table[coliding_prop->offset],
  778. -                                         ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC))
  779. -                             || (Z_LVAL(compare_result) != 0);
  780.                     } else {
  781. -                       not_compatible = (FAILURE == compare_function(&compare_result,
  782. -                                         ce->default_properties_table[coliding_prop->offset],
  783. -                                         ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC))
  784. -                             || (Z_LVAL(compare_result) != 0);
  785. +                       /* the flags are not identical, thus, we assume properties are not compatible */
  786. +                       not_compatible = 1;
  787.                     }
  788. -               } else {
  789. -                   /* the flags are not identical, thus, we assume properties are not compatible */
  790. -                   not_compatible = 1;
  791. -               }
  792.  
  793. -               if (not_compatible) {
  794. -                   zend_error(E_COMPILE_ERROR,
  795. +                   if (not_compatible) {
  796. +                       zend_error(E_COMPILE_ERROR,
  797.                                "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
  798.                                 find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
  799.                                 property_info->ce->name,
  800.                                 prop_name,
  801.                                 ce->name);
  802. -               } else {
  803. -                   zend_error(E_STRICT,
  804. +                   } else {
  805. +                       zend_error(E_STRICT,
  806.                                "%s and %s define the same property ($%s) in the composition of %s. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed",
  807.                                 find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
  808.                                 property_info->ce->name,
  809.                                 prop_name,
  810.                                 ce->name);
  811. +                       continue;
  812. +                   }
  813.                 }
  814.             }
  815.  
  816.             /* property not found, so lets add it */
  817. -           if (property_info->flags & ZEND_ACC_STATIC) {
  818. +           if (flags & ZEND_ACC_STATIC) {
  819.                 prop_value = ce->traits[i]->default_static_members_table[property_info->offset];
  820.             } else {
  821.                 prop_value = ce->traits[i]->default_properties_table[property_info->offset];
  822. @@ -4309,7 +4147,7 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
  823.  
  824.             doc_comment = property_info->doc_comment ? estrndup(property_info->doc_comment, property_info->doc_comment_len) : NULL;
  825.             zend_declare_property_ex(ce, prop_name, prop_name_length,
  826. -                                    prop_value, property_info->flags,
  827. +                                    prop_value, flags,
  828.                                      doc_comment, property_info->doc_comment_len TSRMLS_CC);
  829.         }
  830.     }
  831. @@ -4433,20 +4271,6 @@ ZEND_API int do_bind_function(const zend_op_array *op_array, zend_op *opline, Ha
  832.  }
  833.  /* }}} */
  834.  
  835. -void zend_add_trait_precedence(znode *precedence_znode TSRMLS_DC) /* {{{ */
  836. -{
  837. -   zend_class_entry *ce = CG(active_class_entry);
  838. -   zend_add_to_list(&ce->trait_precedences, precedence_znode->u.op.ptr TSRMLS_CC);
  839. -}
  840. -/* }}} */
  841. -
  842. -void zend_add_trait_alias(znode *alias_znode TSRMLS_DC) /* {{{ */
  843. -{
  844. -   zend_class_entry *ce = CG(active_class_entry);
  845. -   zend_add_to_list(&ce->trait_aliases, alias_znode->u.op.ptr TSRMLS_CC);
  846. -}
  847. -/* }}} */
  848. -
  849.  void zend_prepare_reference(znode *result, znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */
  850.  {
  851.     zend_trait_method_reference *method_ref = emalloc(sizeof(zend_trait_method_reference));
  852. @@ -4471,18 +4295,19 @@ void zend_prepare_reference(znode *result, znode *class_name, znode *method_name
  853.  }
  854.  /* }}} */
  855.  
  856. -void zend_prepare_trait_alias(znode *result, znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC) /* {{{ */
  857. +void zend_add_trait_alias(znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC) /* {{{ */
  858.  {
  859. -   zend_trait_alias *trait_alias = emalloc(sizeof(zend_trait_alias));
  860. +   zend_class_entry *ce = CG(active_class_entry);
  861. +   zend_trait_alias *trait_alias;
  862.  
  863. -   trait_alias->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
  864. -   trait_alias->modifiers = Z_LVAL(modifiers->u.constant);
  865. -  
  866.     if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_STATIC) {
  867.         zend_error(E_COMPILE_ERROR, "Cannot use 'static' as method modifier");
  868.         return;
  869.     }
  870.  
  871. +   trait_alias = emalloc(sizeof(zend_trait_alias));
  872. +   trait_alias->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
  873. +   trait_alias->modifiers = Z_LVAL(modifiers->u.constant);
  874.     if (alias) {
  875.         trait_alias->alias = Z_STRVAL(alias->u.constant);
  876.         trait_alias->alias_len = Z_STRLEN(alias->u.constant);
  877. @@ -4491,12 +4316,13 @@ void zend_prepare_trait_alias(znode *result, znode *method_reference, znode *mod
  878.     }
  879.     trait_alias->function = NULL;
  880.  
  881. -   result->u.op.ptr = trait_alias;
  882. +   zend_add_to_list(&ce->trait_aliases, trait_alias TSRMLS_CC);
  883.  }
  884.  /* }}} */
  885.  
  886. -void zend_prepare_trait_precedence(znode *result, znode *method_reference, znode *trait_list TSRMLS_DC) /* {{{ */
  887. +void zend_add_trait_precedence(znode *method_reference, znode *trait_list TSRMLS_DC) /* {{{ */
  888.  {
  889. +   zend_class_entry *ce = CG(active_class_entry);
  890.     zend_trait_precedence *trait_precedence = emalloc(sizeof(zend_trait_precedence));
  891.  
  892.     trait_precedence->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
  893. @@ -4504,7 +4330,7 @@ void zend_prepare_trait_precedence(znode *result, znode *method_reference, znode
  894.  
  895.     trait_precedence->function = NULL;
  896.  
  897. -   result->u.op.ptr = trait_precedence;
  898. +   zend_add_to_list(&ce->trait_precedences, trait_precedence TSRMLS_CC);
  899.  }
  900.  /* }}} */
  901.  
  902. @@ -4539,7 +4365,7 @@ ZEND_API zend_class_entry *do_bind_class(const zend_op_array* op_array, const ze
  903.         }
  904.         return NULL;
  905.     } else {
  906. -       if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES))) {
  907. +       if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
  908.             zend_verify_abstract_class(ce TSRMLS_CC);
  909.         }
  910.         return ce;
  911. @@ -5109,7 +4935,7 @@ void zend_do_end_class_declaration(const znode *class_token, const znode *parent
  912.     if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
  913.         && ((parent_token->op_type != IS_UNUSED) || (ce->num_interfaces > 0))) {
  914.         zend_verify_abstract_class(ce TSRMLS_CC);
  915. -       if (ce->num_interfaces) {
  916. +       if (ce->num_interfaces && !(ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS)) {
  917.             do_verify_abstract_class(TSRMLS_C);
  918.         }
  919.     }
  920. @@ -5159,9 +4985,10 @@ void zend_do_implements_interface(znode *interface_name TSRMLS_DC) /* {{{ */
  921.  }
  922.  /* }}} */
  923.  
  924. -void zend_do_implements_trait(znode *trait_name TSRMLS_DC) /* {{{ */
  925. +void zend_do_use_trait(znode *trait_name TSRMLS_DC) /* {{{ */
  926.  {
  927.     zend_op *opline;
  928. +
  929.     if ((CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)) {
  930.         zend_error(E_COMPILE_ERROR,
  931.                 "Cannot use traits inside of interfaces. %s is used in %s",
  932. @@ -5891,7 +5718,11 @@ void zend_add_to_list(void *result, void *item TSRMLS_DC) /* {{{ */
  933.     void** list = *(void**)result;
  934.     size_t n = 0;
  935.  
  936. -   while (list && list[n]) { n++; }
  937. +   if (list) {
  938. +       while (list[n]) {
  939. +           n++;
  940. +       }
  941. +   }
  942.  
  943.     list = erealloc(list, sizeof(void*) * (n+2));
  944.  
  945. diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
  946. index 79ace0c..b887a78 100644
  947. --- a/Zend/zend_compile.h
  948. +++ b/Zend/zend_compile.h
  949. @@ -207,8 +207,6 @@ typedef struct _zend_try_catch_element {
  950.  #define ZEND_ACC_RETURN_REFERENCE      0x4000000
  951.  #define ZEND_ACC_DONE_PASS_TWO         0x8000000
  952.  
  953. -#define ZEND_ACC_ALIAS                 0x10000000
  954. -
  955.  char *zend_visibility_string(zend_uint fn_flags);
  956.  
  957.  
  958. @@ -509,16 +507,13 @@ ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry
  959.  void zend_do_implements_interface(znode *interface_znode TSRMLS_DC);
  960.  
  961.  /* Trait related functions */
  962. -void zend_add_trait_precedence(znode *precedence_znode TSRMLS_DC);
  963. -void zend_add_trait_alias(znode *alias_znode TSRMLS_DC);
  964. -
  965. +void zend_do_use_trait(znode *trait_znode TSRMLS_DC);
  966. +void zend_prepare_reference(znode *result, znode *class_name, znode *method_name TSRMLS_DC);
  967. +void zend_add_trait_precedence(znode *method_reference, znode *trait_list TSRMLS_DC);
  968. +void zend_add_trait_alias(znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC);
  969.  
  970. -void zend_do_implements_trait(znode *interface_znode /*, znode* aliases */ TSRMLS_DC);
  971.  ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC);
  972.  ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC);
  973. -void zend_prepare_trait_precedence(znode *result, znode *method_reference, znode *trait_list TSRMLS_DC);
  974. -void zend_prepare_reference(znode *result, znode *class_name, znode *method_name TSRMLS_DC);
  975. -void zend_prepare_trait_alias(znode *result, znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC);
  976.  
  977.  ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC);
  978.  void zend_do_early_binding(TSRMLS_D);
  979. diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
  980. index 9a0b320..92f25f0 100644
  981. --- a/Zend/zend_language_parser.y
  982. +++ b/Zend/zend_language_parser.y
  983. @@ -585,8 +585,8 @@ trait_use_statement:
  984.  ;
  985.  
  986.  trait_list:
  987. -       fully_qualified_class_name                      { zend_do_implements_trait(&$1 TSRMLS_CC); }
  988. -   |   trait_list ',' fully_qualified_class_name       { zend_do_implements_trait(&$3 TSRMLS_CC); }
  989. +       fully_qualified_class_name                      { zend_do_use_trait(&$1 TSRMLS_CC); }
  990. +   |   trait_list ',' fully_qualified_class_name       { zend_do_use_trait(&$3 TSRMLS_CC); }
  991.  ;
  992.  
  993.  trait_adaptations:
  994. @@ -605,12 +605,12 @@ non_empty_trait_adaptation_list:
  995.  ;
  996.  
  997.  trait_adaptation_statement:
  998. -       trait_precedence ';'                                { zend_add_trait_precedence(&$1 TSRMLS_CC); }
  999. -   |   trait_alias ';'                                     { zend_add_trait_alias(&$1 TSRMLS_CC); }
  1000. +       trait_precedence ';'
  1001. +   |   trait_alias ';'
  1002.  ;
  1003.  
  1004.  trait_precedence:
  1005. -   trait_method_reference_fully_qualified T_INSTEADOF trait_reference_list { zend_prepare_trait_precedence(&$$, &$1, &$3 TSRMLS_CC); }
  1006. +   trait_method_reference_fully_qualified T_INSTEADOF trait_reference_list { zend_add_trait_precedence(&$1, &$3 TSRMLS_CC); }
  1007.  ;
  1008.  
  1009.  trait_reference_list:
  1010. @@ -628,8 +628,8 @@ trait_method_reference_fully_qualified:
  1011.  ;
  1012.  
  1013.  trait_alias:
  1014. -       trait_method_reference T_AS trait_modifiers T_STRING        { zend_prepare_trait_alias(&$$, &$1, &$3, &$4 TSRMLS_CC); }
  1015. -   |   trait_method_reference T_AS member_modifier                 { zend_prepare_trait_alias(&$$, &$1, &$3, NULL TSRMLS_CC); }
  1016. +       trait_method_reference T_AS trait_modifiers T_STRING        { zend_add_trait_alias(&$1, &$3, &$4 TSRMLS_CC); }
  1017. +   |   trait_method_reference T_AS member_modifier                 { zend_add_trait_alias(&$1, &$3, NULL TSRMLS_CC); }
  1018.  ;
  1019.  
  1020.  trait_modifiers:
  1021. diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
  1022. index 4c6a784..65fa851 100644
  1023. --- a/Zend/zend_opcode.c
  1024. +++ b/Zend/zend_opcode.c
  1025. @@ -215,12 +215,6 @@ ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC)
  1026.  void _destroy_zend_class_traits_info(zend_class_entry *ce)
  1027.  {
  1028.     if (ce->num_traits > 0 && ce->traits) {
  1029. -       size_t i;
  1030. -       for (i = 0; i < ce->num_traits; i++) {
  1031. -           if (ce->traits[i]) {
  1032. -               destroy_zend_class(&ce->traits[i]);
  1033. -           }
  1034. -       }
  1035.         efree(ce->traits);
  1036.     }
  1037.    
  1038. @@ -267,15 +261,6 @@ void _destroy_zend_class_traits_info(zend_class_entry *ce)
  1039.     }
  1040.  }
  1041.  
  1042. -static int zend_clear_trait_method_name(zend_op_array *op_array TSRMLS_DC)
  1043. -{
  1044. -   if (op_array->function_name && (op_array->fn_flags & ZEND_ACC_ALIAS) == 0) {
  1045. -       efree(op_array->function_name);
  1046. -       op_array->function_name = NULL;
  1047. -   }
  1048. -   return 0;
  1049. -}
  1050. -
  1051.  ZEND_API void destroy_zend_class(zend_class_entry **pce)
  1052.  {
  1053.     zend_class_entry *ce = *pce;
  1054. @@ -307,10 +292,6 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce)
  1055.             }
  1056.             zend_hash_destroy(&ce->properties_info);
  1057.             str_efree(ce->name);
  1058. -           if ((ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
  1059. -               TSRMLS_FETCH();
  1060. -               zend_hash_apply(&ce->function_table, (apply_func_t)zend_clear_trait_method_name TSRMLS_CC);
  1061. -           }
  1062.             zend_hash_destroy(&ce->function_table);
  1063.             zend_hash_destroy(&ce->constants_table);
  1064.             if (ce->num_interfaces > 0 && ce->interfaces) {
  1065. @@ -400,7 +381,7 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC)
  1066.     }
  1067.     efree(op_array->opcodes);
  1068.  
  1069. -   if (op_array->function_name && (op_array->fn_flags & ZEND_ACC_ALIAS) == 0) {
  1070. +   if (op_array->function_name) {
  1071.         efree((char*)op_array->function_name);
  1072.     }
  1073.     if (op_array->doc_comment) {
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement