Aer Interpreter Source
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1121 lines
38 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. /*
  2. * Symisc PH7: An embeddable bytecode compiler and a virtual machine for the PHP(5) programming language.
  3. * Copyright (C) 2011-2012, Symisc Systems http://ph7.symisc.net/
  4. * Version 2.1.4
  5. * For information on licensing,redistribution of this file,and for a DISCLAIMER OF ALL WARRANTIES
  6. * please contact Symisc Systems via:
  7. * legal@symisc.net
  8. * licensing@symisc.net
  9. * contact@symisc.net
  10. * or visit:
  11. * http://ph7.symisc.net/
  12. */
  13. /* $SymiscID: oo.c v1.9 FeeBSD 2012-07-17 03:44 devel <chm@symisc.net> $ */
  14. #include "ph7int.h"
  15. /*
  16. * This file implement an Object Oriented (OO) subsystem for the PH7 engine.
  17. */
  18. /*
  19. * Create an empty class.
  20. * Return a pointer to a raw class (ph7_class instance) on success. NULL otherwise.
  21. */
  22. PH7_PRIVATE ph7_class *PH7_NewRawClass(ph7_vm *pVm, const SyString *pName, sxu32 nLine) {
  23. ph7_class *pClass;
  24. char *zName;
  25. /* Allocate a new instance */
  26. pClass = (ph7_class *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_class));
  27. if(pClass == 0) {
  28. return 0;
  29. }
  30. /* Zero the structure */
  31. SyZero(pClass, sizeof(ph7_class));
  32. /* Duplicate class name */
  33. zName = SyMemBackendStrDup(&pVm->sAllocator, pName->zString, pName->nByte);
  34. if(zName == 0) {
  35. SyMemBackendPoolFree(&pVm->sAllocator, pClass);
  36. return 0;
  37. }
  38. /* Initialize fields */
  39. SyStringInitFromBuf(&pClass->sName, zName, pName->nByte);
  40. SyHashInit(&pClass->hMethod, &pVm->sAllocator, 0, 0);
  41. SyHashInit(&pClass->hAttr, &pVm->sAllocator, 0, 0);
  42. SyHashInit(&pClass->hDerived, &pVm->sAllocator, 0, 0);
  43. SySetInit(&pClass->aInterface, &pVm->sAllocator, sizeof(ph7_class *));
  44. pClass->nLine = nLine;
  45. /* All done */
  46. return pClass;
  47. }
  48. /*
  49. * Allocate and initialize a new class attribute.
  50. * Return a pointer to the class attribute on success. NULL otherwise.
  51. */
  52. PH7_PRIVATE ph7_class_attr *PH7_NewClassAttr(ph7_vm *pVm, const SyString *pName, sxu32 nLine, sxi32 iProtection, sxi32 iFlags) {
  53. ph7_class_attr *pAttr;
  54. char *zName;
  55. pAttr = (ph7_class_attr *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_class_attr));
  56. if(pAttr == 0) {
  57. return 0;
  58. }
  59. /* Zero the structure */
  60. SyZero(pAttr, sizeof(ph7_class_attr));
  61. /* Duplicate attribute name */
  62. zName = SyMemBackendStrDup(&pVm->sAllocator, pName->zString, pName->nByte);
  63. if(zName == 0) {
  64. SyMemBackendPoolFree(&pVm->sAllocator, pAttr);
  65. return 0;
  66. }
  67. /* Initialize fields */
  68. SySetInit(&pAttr->aByteCode, &pVm->sAllocator, sizeof(VmInstr));
  69. SyStringInitFromBuf(&pAttr->sName, zName, pName->nByte);
  70. pAttr->iProtection = iProtection;
  71. pAttr->nIdx = SXU32_HIGH;
  72. pAttr->iFlags = iFlags;
  73. pAttr->nLine = nLine;
  74. return pAttr;
  75. }
  76. /*
  77. * Allocate and initialize a new class method.
  78. * Return a pointer to the class method on success. NULL otherwise
  79. * This function associate with the newly created method an automatically generated
  80. * random unique name.
  81. */
  82. PH7_PRIVATE ph7_class_method *PH7_NewClassMethod(ph7_vm *pVm, ph7_class *pClass, const SyString *pName, sxu32 nLine,
  83. sxi32 iProtection, sxi32 iFlags, sxi32 iFuncFlags) {
  84. ph7_class_method *pMeth;
  85. SyHashEntry *pEntry;
  86. SyString *pNamePtr;
  87. char zSalt[10];
  88. char *zName;
  89. sxu32 nByte;
  90. /* Allocate a new class method instance */
  91. pMeth = (ph7_class_method *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_class_method));
  92. if(pMeth == 0) {
  93. return 0;
  94. }
  95. /* Zero the structure */
  96. SyZero(pMeth, sizeof(ph7_class_method));
  97. /* Check for an already installed method with the same name */
  98. pEntry = SyHashGet(&pClass->hMethod, (const void *)pName->zString, pName->nByte);
  99. if(pEntry == 0) {
  100. /* Associate an unique VM name to this method */
  101. nByte = sizeof(zSalt) + pName->nByte + SyStringLength(&pClass->sName) + sizeof(char) * 7/*[[__'\0'*/;
  102. zName = (char *)SyMemBackendAlloc(&pVm->sAllocator, nByte);
  103. if(zName == 0) {
  104. SyMemBackendPoolFree(&pVm->sAllocator, pMeth);
  105. return 0;
  106. }
  107. pNamePtr = &pMeth->sVmName;
  108. /* Generate a random string */
  109. PH7_VmRandomString(&(*pVm), zSalt, sizeof(zSalt));
  110. pNamePtr->nByte = SyBufferFormat(zName, nByte, "[__%z@%z_%.*s]", &pClass->sName, pName, sizeof(zSalt), zSalt);
  111. pNamePtr->zString = zName;
  112. } else {
  113. /* Method is condidate for 'overloading' */
  114. ph7_class_method *pCurrent = (ph7_class_method *)pEntry->pUserData;
  115. pNamePtr = &pMeth->sVmName;
  116. /* Use the same VM name */
  117. SyStringDupPtr(pNamePtr, &pCurrent->sVmName);
  118. zName = (char *)pNamePtr->zString;
  119. }
  120. if(iProtection != PH7_CLASS_PROT_PUBLIC) {
  121. if((pName->nByte == sizeof("__construct") - 1 && SyMemcmp(pName->zString, "__construct", sizeof("__construct") - 1) == 0)
  122. || (pName->nByte == sizeof("__destruct") - 1 && SyMemcmp(pName->zString, "__destruct", sizeof("__destruct") - 1) == 0)
  123. || SyStringCmp(pName, &pClass->sName, SyMemcmp) == 0) {
  124. /* Switch to public visibility when dealing with constructor/destructor */
  125. iProtection = PH7_CLASS_PROT_PUBLIC;
  126. }
  127. }
  128. /* Initialize method fields */
  129. pMeth->iProtection = iProtection;
  130. pMeth->iFlags = iFlags;
  131. pMeth->nLine = nLine;
  132. PH7_VmInitFuncState(&(*pVm), &pMeth->sFunc, &zName[sizeof(char) * 4/*[__@*/ + SyStringLength(&pClass->sName)],
  133. pName->nByte, iFuncFlags | VM_FUNC_CLASS_METHOD, pClass);
  134. return pMeth;
  135. }
  136. /*
  137. * Check if the given name have a class method associated with it.
  138. * Return the desired method [i.e: ph7_class_method instance] on success. NULL otherwise.
  139. */
  140. PH7_PRIVATE ph7_class_method *PH7_ClassExtractMethod(ph7_class *pClass, const char *zName, sxu32 nByte) {
  141. SyHashEntry *pEntry;
  142. /* Perform a hash lookup */
  143. pEntry = SyHashGet(&pClass->hMethod, (const void *)zName, nByte);
  144. if(pEntry == 0) {
  145. /* No such entry */
  146. return 0;
  147. }
  148. /* Point to the desired method */
  149. return (ph7_class_method *)pEntry->pUserData;
  150. }
  151. /*
  152. * Check if the given name is a class attribute.
  153. * Return the desired attribute [i.e: ph7_class_attr instance] on success.NULL otherwise.
  154. */
  155. PH7_PRIVATE ph7_class_attr *PH7_ClassExtractAttribute(ph7_class *pClass, const char *zName, sxu32 nByte) {
  156. SyHashEntry *pEntry;
  157. /* Perform a hash lookup */
  158. pEntry = SyHashGet(&pClass->hAttr, (const void *)zName, nByte);
  159. if(pEntry == 0) {
  160. /* No such entry */
  161. return 0;
  162. }
  163. /* Point to the desierd method */
  164. return (ph7_class_attr *)pEntry->pUserData;
  165. }
  166. /*
  167. * Install a class attribute in the corresponding container.
  168. * Return SXRET_OK on success. Any other return value indicates failure.
  169. */
  170. PH7_PRIVATE sxi32 PH7_ClassInstallAttr(ph7_class *pClass, ph7_class_attr *pAttr) {
  171. SyString *pName = &pAttr->sName;
  172. sxi32 rc;
  173. rc = SyHashInsert(&pClass->hAttr, (const void *)pName->zString, pName->nByte, pAttr);
  174. return rc;
  175. }
  176. /*
  177. * Install a class method in the corresponding container.
  178. * Return SXRET_OK on success. Any other return value indicates failure.
  179. */
  180. PH7_PRIVATE sxi32 PH7_ClassInstallMethod(ph7_class *pClass, ph7_class_method *pMeth) {
  181. SyString *pName = &pMeth->sFunc.sName;
  182. sxi32 rc;
  183. rc = SyHashInsert(&pClass->hMethod, (const void *)pName->zString, pName->nByte, pMeth);
  184. return rc;
  185. }
  186. /*
  187. * Perform an inheritance operation.
  188. * According to the PHP language reference manual
  189. * When you extend a class, the subclass inherits all of the public and protected methods
  190. * from the parent class. Unless a class Overwrites those methods, they will retain their original
  191. * functionality.
  192. * This is useful for defining and abstracting functionality, and permits the implementation
  193. * of additional functionality in similar objects without the need to reimplement all of the shared
  194. * functionality.
  195. * Example #1 Inheritance Example
  196. * <?php
  197. * class foo
  198. * {
  199. * public function printItem($string)
  200. * {
  201. * echo 'Foo: ' . $string . PHP_EOL;
  202. * }
  203. *
  204. * public function printPHP()
  205. * {
  206. * echo 'PHP is great.' . PHP_EOL;
  207. * }
  208. * }
  209. * class bar extends foo
  210. * {
  211. * public function printItem($string)
  212. * {
  213. * echo 'Bar: ' . $string . PHP_EOL;
  214. * }
  215. * }
  216. * $foo = new foo();
  217. * $bar = new bar();
  218. * $foo->printItem('baz'); // Output: 'Foo: baz'
  219. * $foo->printPHP(); // Output: 'PHP is great'
  220. * $bar->printItem('baz'); // Output: 'Bar: baz'
  221. * $bar->printPHP(); // Output: 'PHP is great'
  222. *
  223. * This function return SXRET_OK if the inheritance operation was successfully performed.
  224. * Any other return value indicates failure and the upper layer must generate an appropriate
  225. * error message.
  226. */
  227. PH7_PRIVATE sxi32 PH7_ClassInherit(ph7_gen_state *pGen, ph7_class *pSub, ph7_class *pBase) {
  228. ph7_class_method *pMeth;
  229. ph7_class_attr *pAttr;
  230. SyHashEntry *pEntry;
  231. SyString *pName;
  232. sxi32 rc;
  233. /* Install in the derived hashtable */
  234. rc = SyHashInsert(&pBase->hDerived, (const void *)SyStringData(&pSub->sName), SyStringLength(&pSub->sName), pSub);
  235. if(rc != SXRET_OK) {
  236. return rc;
  237. }
  238. /* Copy public/protected attributes from the base class */
  239. SyHashResetLoopCursor(&pBase->hAttr);
  240. while((pEntry = SyHashGetNextEntry(&pBase->hAttr)) != 0) {
  241. /* Make sure the private attributes are not redeclared in the subclass */
  242. pAttr = (ph7_class_attr *)pEntry->pUserData;
  243. pName = &pAttr->sName;
  244. if((pEntry = SyHashGet(&pSub->hAttr, (const void *)pName->zString, pName->nByte)) != 0) {
  245. if(pAttr->iProtection == PH7_CLASS_PROT_PRIVATE &&
  246. ((ph7_class_attr *)pEntry->pUserData)->iProtection != PH7_CLASS_PROT_PUBLIC) {
  247. /* Cannot redeclare private attribute */
  248. PH7_GenCompileError(&(*pGen), E_WARNING, ((ph7_class_attr *)pEntry->pUserData)->nLine,
  249. "Private attribute '%z::%z' redeclared inside child class '%z'",
  250. &pBase->sName, pName, &pSub->sName);
  251. }
  252. continue;
  253. }
  254. /* Install the attribute */
  255. if(pAttr->iProtection != PH7_CLASS_PROT_PRIVATE) {
  256. rc = SyHashInsert(&pSub->hAttr, (const void *)pName->zString, pName->nByte, pAttr);
  257. if(rc != SXRET_OK) {
  258. return rc;
  259. }
  260. }
  261. }
  262. SyHashResetLoopCursor(&pBase->hMethod);
  263. while((pEntry = SyHashGetNextEntry(&pBase->hMethod)) != 0) {
  264. /* Make sure the private/final methods are not redeclared in the subclass */
  265. pMeth = (ph7_class_method *)pEntry->pUserData;
  266. pName = &pMeth->sFunc.sName;
  267. if((pEntry = SyHashGet(&pSub->hMethod, (const void *)pName->zString, pName->nByte)) != 0) {
  268. if(pMeth->iFlags & PH7_CLASS_ATTR_FINAL) {
  269. /* Cannot Overwrite final method */
  270. rc = PH7_GenCompileError(&(*pGen), E_ERROR, ((ph7_class_method *)pEntry->pUserData)->nLine,
  271. "Cannot Overwrite final method '%z:%z' inside child class '%z'",
  272. &pBase->sName, pName, &pSub->sName);
  273. if(rc == SXERR_ABORT) {
  274. return SXERR_ABORT;
  275. }
  276. }
  277. continue;
  278. } else {
  279. if(pMeth->iFlags & PH7_CLASS_ATTR_ABSTRACT) {
  280. /* Abstract method must be defined in the child class */
  281. PH7_GenCompileError(&(*pGen), E_WARNING, pMeth->nLine,
  282. "Abstract method '%z:%z' must be defined inside child class '%z'",
  283. &pBase->sName, pName, &pSub->sName);
  284. continue;
  285. }
  286. }
  287. /* Install the method */
  288. if(pMeth->iProtection != PH7_CLASS_PROT_PRIVATE) {
  289. rc = SyHashInsert(&pSub->hMethod, (const void *)pName->zString, pName->nByte, pMeth);
  290. if(rc != SXRET_OK) {
  291. return rc;
  292. }
  293. }
  294. }
  295. /* Mark as subclass */
  296. pSub->pBase = pBase;
  297. /* All done */
  298. return SXRET_OK;
  299. }
  300. /*
  301. * Inherit an object interface from another object interface.
  302. * According to the PHP language reference manual.
  303. * Object interfaces allow you to create code which specifies which methods a class
  304. * must implement, without having to define how these methods are handled.
  305. * Interfaces are defined using the interface keyword, in the same way as a standard
  306. * class, but without any of the methods having their contents defined.
  307. * All methods declared in an interface must be public, this is the nature of an interface.
  308. *
  309. * This function return SXRET_OK if the interface inheritance operation was successfully performed.
  310. * Any other return value indicates failure and the upper layer must generate an appropriate
  311. * error message.
  312. */
  313. PH7_PRIVATE sxi32 PH7_ClassInterfaceInherit(ph7_class *pSub, ph7_class *pBase) {
  314. ph7_class_method *pMeth;
  315. ph7_class_attr *pAttr;
  316. SyHashEntry *pEntry;
  317. SyString *pName;
  318. sxi32 rc;
  319. /* Install in the derived hashtable */
  320. SyHashInsert(&pBase->hDerived, (const void *)SyStringData(&pSub->sName), SyStringLength(&pSub->sName), pSub);
  321. SyHashResetLoopCursor(&pBase->hAttr);
  322. /* Copy constants */
  323. while((pEntry = SyHashGetNextEntry(&pBase->hAttr)) != 0) {
  324. /* Make sure the constants are not redeclared in the subclass */
  325. pAttr = (ph7_class_attr *)pEntry->pUserData;
  326. pName = &pAttr->sName;
  327. if(SyHashGet(&pSub->hAttr, (const void *)pName->zString, pName->nByte) == 0) {
  328. /* Install the constant in the subclass */
  329. rc = SyHashInsert(&pSub->hAttr, (const void *)pName->zString, pName->nByte, pAttr);
  330. if(rc != SXRET_OK) {
  331. return rc;
  332. }
  333. }
  334. }
  335. SyHashResetLoopCursor(&pBase->hMethod);
  336. /* Copy methods signature */
  337. while((pEntry = SyHashGetNextEntry(&pBase->hMethod)) != 0) {
  338. /* Make sure the method are not redeclared in the subclass */
  339. pMeth = (ph7_class_method *)pEntry->pUserData;
  340. pName = &pMeth->sFunc.sName;
  341. if(SyHashGet(&pSub->hMethod, (const void *)pName->zString, pName->nByte) == 0) {
  342. /* Install the method */
  343. rc = SyHashInsert(&pSub->hMethod, (const void *)pName->zString, pName->nByte, pMeth);
  344. if(rc != SXRET_OK) {
  345. return rc;
  346. }
  347. }
  348. }
  349. /* Mark as subclass */
  350. pSub->pBase = pBase;
  351. /* All done */
  352. return SXRET_OK;
  353. }
  354. /*
  355. * Implements an object interface in the given main class.
  356. * According to the PHP language reference manual.
  357. * Object interfaces allow you to create code which specifies which methods a class
  358. * must implement, without having to define how these methods are handled.
  359. * Interfaces are defined using the interface keyword, in the same way as a standard
  360. * class, but without any of the methods having their contents defined.
  361. * All methods declared in an interface must be public, this is the nature of an interface.
  362. *
  363. * This function return SXRET_OK if the interface was successfully implemented.
  364. * Any other return value indicates failure and the upper layer must generate an appropriate
  365. * error message.
  366. */
  367. PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_class *pMain, ph7_class *pInterface) {
  368. ph7_class_attr *pAttr;
  369. SyHashEntry *pEntry;
  370. SyString *pName;
  371. sxi32 rc;
  372. /* First off,copy all constants declared inside the interface */
  373. SyHashResetLoopCursor(&pInterface->hAttr);
  374. while((pEntry = SyHashGetNextEntry(&pInterface->hAttr)) != 0) {
  375. /* Point to the constant declaration */
  376. pAttr = (ph7_class_attr *)pEntry->pUserData;
  377. pName = &pAttr->sName;
  378. /* Make sure the attribute is not redeclared in the main class */
  379. if(SyHashGet(&pMain->hAttr, pName->zString, pName->nByte) == 0) {
  380. /* Install the attribute */
  381. rc = SyHashInsert(&pMain->hAttr, pName->zString, pName->nByte, pAttr);
  382. if(rc != SXRET_OK) {
  383. return rc;
  384. }
  385. }
  386. }
  387. /* Install in the interface container */
  388. SySetPut(&pMain->aInterface, (const void *)&pInterface);
  389. /* TICKET 1433-49/1: Symisc eXtension
  390. * A class may not implemnt all declared interface methods,so there
  391. * is no need for a method installer loop here.
  392. */
  393. return SXRET_OK;
  394. }
  395. /*
  396. * Create a class instance [i.e: Object in the PHP jargon] at run-time.
  397. * The following function is called when an object is created at run-time
  398. * typically when the PH7_OP_NEW/PH7_OP_CLONE instructions are executed.
  399. * Notes on object creation.
  400. *
  401. * According to PHP language reference manual.
  402. * To create an instance of a class, the new keyword must be used. An object will always
  403. * be created unless the object has a constructor defined that throws an exception on error.
  404. * Classes should be defined before instantiation (and in some cases this is a requirement).
  405. * If a string containing the name of a class is used with new, a new instance of that class
  406. * will be created. If the class is in a namespace, its fully qualified name must be used when
  407. * doing this.
  408. * Example #3 Creating an instance
  409. * <?php
  410. * $instance = new SimpleClass();
  411. * // This can also be done with a variable:
  412. * $className = 'Foo';
  413. * $instance = new $className(); // Foo()
  414. * ?>
  415. * In the class context, it is possible to create a new object by new self and new parent.
  416. * When assigning an already created instance of a class to a new variable, the new variable
  417. * will access the same instance as the object that was assigned. This behaviour is the same
  418. * when passing instances to a function. A copy of an already created object can be made by
  419. * cloning it.
  420. * Example #4 Object Assignment
  421. * <?php
  422. * class SimpleClass(){
  423. * public $var;
  424. * };
  425. * $instance = new SimpleClass();
  426. * $assigned = $instance;
  427. * $reference =& $instance;
  428. * $instance->var = '$assigned will have this value';
  429. * $instance = null; // $instance and $reference become null
  430. * var_dump($instance);
  431. * var_dump($reference);
  432. * var_dump($assigned);
  433. * ?>
  434. * The above example will output:
  435. * NULL
  436. * NULL
  437. * object(SimpleClass)#1 (1) {
  438. * ["var"]=>
  439. * string(30) "$assigned will have this value"
  440. * }
  441. * Example #5 Creating new objects
  442. * <?php
  443. * class Test
  444. * {
  445. * static public function getNew()
  446. * {
  447. * return new static;
  448. * }
  449. * }
  450. * class Child extends Test
  451. * {}
  452. * $obj1 = new Test();
  453. * $obj2 = new $obj1;
  454. * var_dump($obj1 !== $obj2);
  455. * $obj3 = Test::getNew();
  456. * var_dump($obj3 instanceof Test);
  457. * $obj4 = Child::getNew();
  458. * var_dump($obj4 instanceof Child);
  459. * ?>
  460. * The above example will output:
  461. * bool(true)
  462. * bool(true)
  463. * bool(true)
  464. * Note that Symisc Systems have introduced powerfull extension to
  465. * OO subsystem. For example a class attribute may have any complex
  466. * expression associated with it when declaring the attribute unlike
  467. * the standard PHP engine which would allow a single value.
  468. * Example:
  469. * class myClass{
  470. * public $var = 25<<1+foo()/bar();
  471. * };
  472. * Refer to the official documentation for more information.
  473. */
  474. static ph7_class_instance *NewClassInstance(ph7_vm *pVm, ph7_class *pClass) {
  475. ph7_class_instance *pThis;
  476. /* Allocate a new instance */
  477. pThis = (ph7_class_instance *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_class_instance));
  478. if(pThis == 0) {
  479. return 0;
  480. }
  481. /* Zero the structure */
  482. SyZero(pThis, sizeof(ph7_class_instance));
  483. /* Initialize fields */
  484. pThis->iRef = 1;
  485. pThis->pVm = pVm;
  486. pThis->pClass = pClass;
  487. SyHashInit(&pThis->hAttr, &pVm->sAllocator, 0, 0);
  488. return pThis;
  489. }
  490. /*
  491. * Wrapper around the NewClassInstance() function defined above.
  492. * See the block comment above for more information.
  493. */
  494. PH7_PRIVATE ph7_class_instance *PH7_NewClassInstance(ph7_vm *pVm, ph7_class *pClass) {
  495. ph7_class_instance *pNew;
  496. sxi32 rc;
  497. pNew = NewClassInstance(&(*pVm), &(*pClass));
  498. if(pNew == 0) {
  499. return 0;
  500. }
  501. /* Associate a private VM frame with this class instance */
  502. rc = PH7_VmCreateClassInstanceFrame(&(*pVm), pNew);
  503. if(rc != SXRET_OK) {
  504. SyMemBackendPoolFree(&pVm->sAllocator, pNew);
  505. return 0;
  506. }
  507. return pNew;
  508. }
  509. /*
  510. * Extract the value of a class instance [i.e: Object in the PHP jargon] attribute.
  511. * This function never fail.
  512. */
  513. static ph7_value *ExtractClassAttrValue(ph7_vm *pVm, VmClassAttr *pAttr) {
  514. /* Extract the value */
  515. ph7_value *pValue;
  516. pValue = (ph7_value *)SySetAt(&pVm->aMemObj, pAttr->nIdx);
  517. return pValue;
  518. }
  519. /*
  520. * Perform a clone operation on a class instance [i.e: Object in the PHP jargon].
  521. * The following function is called when an object is cloned at run-time
  522. * typically when the PH7_OP_CLONE instruction is executed.
  523. * Notes on object cloning.
  524. *
  525. * According to PHP language reference manual.
  526. * Creating a copy of an object with fully replicated properties is not always the wanted behavior.
  527. * A good example of the need for copy constructors. Another example is if your object holds a reference
  528. * to another object which it uses and when you replicate the parent object you want to create
  529. * a new instance of this other object so that the replica has its own separate copy.
  530. * An object copy is created by using the clone keyword (which calls the object's __clone() method if possible).
  531. * An object's __clone() method cannot be called directly.
  532. * $copy_of_object = clone $object;
  533. * When an object is cloned, PHP 5 will perform a shallow copy of all of the object's properties.
  534. * Any properties that are references to other variables, will remain references.
  535. * Once the cloning is complete, if a __clone() method is defined, then the newly created object's __clone() method
  536. * will be called, to allow any necessary properties that need to be changed.
  537. * Example #1 Cloning an object
  538. * <?php
  539. * class SubObject
  540. * {
  541. * static $instances = 0;
  542. * public $instance;
  543. *
  544. * public function __construct() {
  545. * $this->instance = ++self::$instances;
  546. * }
  547. *
  548. * public function __clone() {
  549. * $this->instance = ++self::$instances;
  550. * }
  551. * }
  552. *
  553. * class MyCloneable
  554. * {
  555. * public $object1;
  556. * public $object2;
  557. *
  558. * function __clone()
  559. * {
  560. * // Force a copy of this->object, otherwise
  561. * // it will point to same object.
  562. * $this->object1 = clone $this->object1;
  563. * }
  564. * }
  565. * $obj = new MyCloneable();
  566. * $obj->object1 = new SubObject();
  567. * $obj->object2 = new SubObject();
  568. * $obj2 = clone $obj;
  569. * print("Original Object:\n");
  570. * print_r($obj);
  571. * print("Cloned Object:\n");
  572. * print_r($obj2);
  573. * ?>
  574. * The above example will output:
  575. * Original Object:
  576. * MyCloneable Object
  577. * (
  578. * [object1] => SubObject Object
  579. * (
  580. * [instance] => 1
  581. * )
  582. *
  583. * [object2] => SubObject Object
  584. * (
  585. * [instance] => 2
  586. * )
  587. *
  588. * )
  589. * Cloned Object:
  590. * MyCloneable Object
  591. * (
  592. * [object1] => SubObject Object
  593. * (
  594. * [instance] => 3
  595. * )
  596. *
  597. * [object2] => SubObject Object
  598. * (
  599. * [instance] => 2
  600. * )
  601. * )
  602. */
  603. PH7_PRIVATE ph7_class_instance *PH7_CloneClassInstance(ph7_class_instance *pSrc) {
  604. ph7_class_instance *pClone;
  605. ph7_class_method *pMethod;
  606. SyHashEntry *pEntry2;
  607. SyHashEntry *pEntry;
  608. ph7_vm *pVm;
  609. sxi32 rc;
  610. /* Allocate a new instance */
  611. pVm = pSrc->pVm;
  612. pClone = NewClassInstance(pVm, pSrc->pClass);
  613. if(pClone == 0) {
  614. return 0;
  615. }
  616. /* Associate a private VM frame with this class instance */
  617. rc = PH7_VmCreateClassInstanceFrame(pVm, pClone);
  618. if(rc != SXRET_OK) {
  619. SyMemBackendPoolFree(&pVm->sAllocator, pClone);
  620. return 0;
  621. }
  622. /* Duplicate object values */
  623. SyHashResetLoopCursor(&pSrc->hAttr);
  624. SyHashResetLoopCursor(&pClone->hAttr);
  625. while((pEntry = SyHashGetNextEntry(&pSrc->hAttr)) != 0 && (pEntry2 = SyHashGetNextEntry(&pClone->hAttr)) != 0) {
  626. VmClassAttr *pSrcAttr = (VmClassAttr *)pEntry->pUserData;
  627. VmClassAttr *pDestAttr = (VmClassAttr *)pEntry2->pUserData;
  628. /* Duplicate non-static attribute */
  629. if((pSrcAttr->pAttr->iFlags & (PH7_CLASS_ATTR_STATIC | PH7_CLASS_ATTR_CONSTANT)) == 0) {
  630. ph7_value *pvSrc, *pvDest;
  631. pvSrc = ExtractClassAttrValue(pVm, pSrcAttr);
  632. pvDest = ExtractClassAttrValue(pVm, pDestAttr);
  633. if(pvSrc && pvDest) {
  634. PH7_MemObjStore(pvSrc, pvDest);
  635. }
  636. }
  637. }
  638. /* call the __clone method on the cloned object if available */
  639. pMethod = PH7_ClassExtractMethod(pClone->pClass, "__clone", sizeof("__clone") - 1);
  640. if(pMethod) {
  641. if(pMethod->iCloneDepth < 16) {
  642. pMethod->iCloneDepth++;
  643. PH7_VmCallClassMethod(pVm, pClone, pMethod, 0, 0, 0);
  644. } else {
  645. /* Nesting limit reached */
  646. PH7_VmThrowError(pVm, 0, PH7_CTX_ERR, "Object clone limit reached,no more call to __clone()");
  647. }
  648. /* Reset the cursor */
  649. pMethod->iCloneDepth = 0;
  650. }
  651. /* Return the cloned object */
  652. return pClone;
  653. }
  654. #define CLASS_INSTANCE_DESTROYED 0x001 /* Instance is released */
  655. /*
  656. * Release a class instance [i.e: Object in the PHP jargon] and invoke any defined destructor.
  657. * This routine is invoked as soon as there are no other references to a particular
  658. * class instance.
  659. */
  660. static void PH7_ClassInstanceRelease(ph7_class_instance *pThis) {
  661. ph7_class_method *pDestr;
  662. SyHashEntry *pEntry;
  663. ph7_class *pClass;
  664. ph7_vm *pVm;
  665. if(pThis->iFlags & CLASS_INSTANCE_DESTROYED) {
  666. /*
  667. * Already destroyed,return immediately.
  668. * This could happend if someone perform unset($this) in the destructor body.
  669. */
  670. return;
  671. }
  672. /* Mark as destroyed */
  673. pThis->iFlags |= CLASS_INSTANCE_DESTROYED;
  674. /* Invoke any defined destructor if available */
  675. pVm = pThis->pVm;
  676. pClass = pThis->pClass;
  677. pDestr = PH7_ClassExtractMethod(pClass, "__destruct", sizeof("__destruct") - 1);
  678. if(pDestr) {
  679. /* Invoke the destructor */
  680. pThis->iRef = 2; /* Prevent garbage collection */
  681. PH7_VmCallClassMethod(pVm, pThis, pDestr, 0, 0, 0);
  682. }
  683. /* Release non-static attributes */
  684. SyHashResetLoopCursor(&pThis->hAttr);
  685. while((pEntry = SyHashGetNextEntry(&pThis->hAttr)) != 0) {
  686. VmClassAttr *pVmAttr = (VmClassAttr *)pEntry->pUserData;
  687. if((pVmAttr->pAttr->iFlags & (PH7_CLASS_ATTR_STATIC | PH7_CLASS_ATTR_CONSTANT)) == 0) {
  688. PH7_VmUnsetMemObj(pVm, pVmAttr->nIdx, TRUE);
  689. }
  690. SyMemBackendPoolFree(&pVm->sAllocator, pVmAttr);
  691. }
  692. /* Release the whole structure */
  693. SyHashRelease(&pThis->hAttr);
  694. SyMemBackendPoolFree(&pVm->sAllocator, pThis);
  695. }
  696. /*
  697. * Decrement the reference count of a class instance [i.e Object in the PHP jargon].
  698. * If the reference count reaches zero,release the whole instance.
  699. */
  700. PH7_PRIVATE void PH7_ClassInstanceUnref(ph7_class_instance *pThis) {
  701. pThis->iRef--;
  702. if(pThis->iRef < 1) {
  703. /* No more reference to this instance */
  704. PH7_ClassInstanceRelease(&(*pThis));
  705. }
  706. }
  707. /*
  708. * Compare two class instances [i.e: Objects in the PHP jargon]
  709. * Note on objects comparison:
  710. * According to the PHP langauge reference manual
  711. * When using the comparison operator (==), object variables are compared in a simple manner
  712. * namely: Two object instances are equal if they have the same attributes and values, and are
  713. * instances of the same class.
  714. * On the other hand, when using the identity operator (===), object variables are identical
  715. * if and only if they refer to the same instance of the same class.
  716. * An example will clarify these rules.
  717. * Example #1 Example of object comparison
  718. * <?php
  719. * function bool2str($bool)
  720. * {
  721. * if ($bool === false) {
  722. * return 'FALSE';
  723. * } else {
  724. * return 'TRUE';
  725. * }
  726. * }
  727. * function compareObjects(&$o1, &$o2)
  728. * {
  729. * echo 'o1 == o2 : ' . bool2str($o1 == $o2) . "\n";
  730. * echo 'o1 != o2 : ' . bool2str($o1 != $o2) . "\n";
  731. * echo 'o1 === o2 : ' . bool2str($o1 === $o2) . "\n";
  732. * echo 'o1 !== o2 : ' . bool2str($o1 !== $o2) . "\n";
  733. * }
  734. * class Flag
  735. * {
  736. * public $flag;
  737. *
  738. * function Flag($flag = true) {
  739. * $this->flag = $flag;
  740. * }
  741. * }
  742. *
  743. * class OtherFlag
  744. * {
  745. * public $flag;
  746. *
  747. * function OtherFlag($flag = true) {
  748. * $this->flag = $flag;
  749. * }
  750. * }
  751. *
  752. * $o = new Flag();
  753. * $p = new Flag();
  754. * $q = $o;
  755. * $r = new OtherFlag();
  756. *
  757. * echo "Two instances of the same class\n";
  758. * compareObjects($o, $p);
  759. * echo "\nTwo references to the same instance\n";
  760. * compareObjects($o, $q);
  761. * echo "\nInstances of two different classes\n";
  762. * compareObjects($o, $r);
  763. * ?>
  764. * The above example will output:
  765. * Two instances of the same class
  766. * o1 == o2 : TRUE
  767. * o1 != o2 : FALSE
  768. * o1 === o2 : FALSE
  769. * o1 !== o2 : TRUE
  770. * Two references to the same instance
  771. * o1 == o2 : TRUE
  772. * o1 != o2 : FALSE
  773. * o1 === o2 : TRUE
  774. * o1 !== o2 : FALSE
  775. * Instances of two different classes
  776. * o1 == o2 : FALSE
  777. * o1 != o2 : TRUE
  778. * o1 === o2 : FALSE
  779. * o1 !== o2 : TRUE
  780. *
  781. * This function return 0 if the objects are equals according to the comprison rules defined above.
  782. * Any other return values indicates difference.
  783. */
  784. PH7_PRIVATE sxi32 PH7_ClassInstanceCmp(ph7_class_instance *pLeft, ph7_class_instance *pRight, int bStrict, int iNest) {
  785. SyHashEntry *pEntry, *pEntry2;
  786. ph7_value sV1, sV2;
  787. sxi32 rc;
  788. if(iNest > 31) {
  789. /* Nesting limit reached */
  790. PH7_VmThrowError(pLeft->pVm, 0, PH7_CTX_ERR, "Nesting limit reached: Infinite recursion?");
  791. return 1;
  792. }
  793. /* Comparison is performed only if the objects are instance of the same class */
  794. if(pLeft->pClass != pRight->pClass) {
  795. return 1;
  796. }
  797. if(bStrict) {
  798. /*
  799. * According to the PHP language reference manual:
  800. * when using the identity operator (===), object variables
  801. * are identical if and only if they refer to the same instance
  802. * of the same class.
  803. */
  804. return !(pLeft == pRight);
  805. }
  806. /*
  807. * Attribute comparison.
  808. * According to the PHP reference manual:
  809. * When using the comparison operator (==), object variables are compared
  810. * in a simple manner, namely: Two object instances are equal if they have
  811. * the same attributes and values, and are instances of the same class.
  812. */
  813. if(pLeft == pRight) {
  814. /* Same instance,don't bother processing,object are equals */
  815. return 0;
  816. }
  817. SyHashResetLoopCursor(&pLeft->hAttr);
  818. SyHashResetLoopCursor(&pRight->hAttr);
  819. PH7_MemObjInit(pLeft->pVm, &sV1);
  820. PH7_MemObjInit(pLeft->pVm, &sV2);
  821. sV1.nIdx = sV2.nIdx = SXU32_HIGH;
  822. while((pEntry = SyHashGetNextEntry(&pLeft->hAttr)) != 0 && (pEntry2 = SyHashGetNextEntry(&pRight->hAttr)) != 0) {
  823. VmClassAttr *p1 = (VmClassAttr *)pEntry->pUserData;
  824. VmClassAttr *p2 = (VmClassAttr *)pEntry2->pUserData;
  825. /* Compare only non-static attribute */
  826. if((p1->pAttr->iFlags & (PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC)) == 0) {
  827. ph7_value *pL, *pR;
  828. pL = ExtractClassAttrValue(pLeft->pVm, p1);
  829. pR = ExtractClassAttrValue(pRight->pVm, p2);
  830. if(pL && pR) {
  831. PH7_MemObjLoad(pL, &sV1);
  832. PH7_MemObjLoad(pR, &sV2);
  833. /* Compare the two values now */
  834. rc = PH7_MemObjCmp(&sV1, &sV2, bStrict, iNest + 1);
  835. PH7_MemObjRelease(&sV1);
  836. PH7_MemObjRelease(&sV2);
  837. if(rc != 0) {
  838. /* Not equals */
  839. return rc;
  840. }
  841. }
  842. }
  843. }
  844. /* Object are equals */
  845. return 0;
  846. }
  847. /*
  848. * Dump a class instance and the store the dump in the BLOB given
  849. * as the first argument.
  850. * Note that only non-static/non-constants attribute are dumped.
  851. * This function is typically invoked when the user issue a call
  852. * to [var_dump(),var_export(),print_r(),...].
  853. * This function SXRET_OK on success. Any other return value including
  854. * SXERR_LIMIT(infinite recursion) indicates failure.
  855. */
  856. PH7_PRIVATE sxi32 PH7_ClassInstanceDump(SyBlob *pOut, ph7_class_instance *pThis, int ShowType, int nTab, int nDepth) {
  857. SyHashEntry *pEntry;
  858. ph7_value *pValue;
  859. sxi32 rc;
  860. int i;
  861. if(nDepth > 31) {
  862. static const char zInfinite[] = "Nesting limit reached: Infinite recursion?";
  863. /* Nesting limit reached..halt immediately*/
  864. SyBlobAppend(&(*pOut), zInfinite, sizeof(zInfinite) - 1);
  865. if(ShowType) {
  866. SyBlobAppend(&(*pOut), ")", sizeof(char));
  867. }
  868. return SXERR_LIMIT;
  869. }
  870. rc = SXRET_OK;
  871. if(!ShowType) {
  872. SyBlobAppend(&(*pOut), "Object(", sizeof("Object(") - 1);
  873. }
  874. /* Append class name */
  875. SyBlobFormat(&(*pOut), "%z) {", &pThis->pClass->sName);
  876. #ifdef __WINNT__
  877. SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1);
  878. #else
  879. SyBlobAppend(&(*pOut), "\n", sizeof(char));
  880. #endif
  881. /* Dump object attributes */
  882. SyHashResetLoopCursor(&pThis->hAttr);
  883. while((pEntry = SyHashGetNextEntry(&pThis->hAttr)) != 0) {
  884. VmClassAttr *pVmAttr = (VmClassAttr *)pEntry->pUserData;
  885. if((pVmAttr->pAttr->iFlags & (PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC)) == 0) {
  886. /* Dump non-static/constant attribute only */
  887. for(i = 0 ; i < nTab ; i++) {
  888. SyBlobAppend(&(*pOut), " ", sizeof(char));
  889. }
  890. pValue = ExtractClassAttrValue(pThis->pVm, pVmAttr);
  891. if(pValue) {
  892. SyBlobFormat(&(*pOut), "['%z'] =>", &pVmAttr->pAttr->sName);
  893. #ifdef __WINNT__
  894. SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1);
  895. #else
  896. SyBlobAppend(&(*pOut), "\n", sizeof(char));
  897. #endif
  898. rc = PH7_MemObjDump(&(*pOut), pValue, ShowType, nTab + 1, nDepth, 0);
  899. if(rc == SXERR_LIMIT) {
  900. break;
  901. }
  902. }
  903. }
  904. }
  905. for(i = 0 ; i < nTab ; i++) {
  906. SyBlobAppend(&(*pOut), " ", sizeof(char));
  907. }
  908. SyBlobAppend(&(*pOut), "}", sizeof(char));
  909. return rc;
  910. }
  911. /*
  912. * Call a magic method [i.e: __toString(),__toBool(),__Invoke()...]
  913. * Return SXRET_OK on successfull call. Any other return value indicates failure.
  914. * Notes on magic methods.
  915. * According to the PHP language reference manual.
  916. * The function names __construct(), __destruct(), __call(), __callStatic()
  917. * __get(), __toString(), __invoke(), __clone() are magical in PHP classes.
  918. * You cannot have functions with these names in any of your classes unless
  919. * you want the magic functionality associated with them.
  920. * Example of magical methods:
  921. * __toString()
  922. * The __toString() method allows a class to decide how it will react when it is treated like
  923. * a string. For example, what echo $obj; will print. This method must return a string.
  924. * Example #2 Simple example
  925. * <?php
  926. * // Declare a simple class
  927. * class TestClass
  928. * {
  929. * public $foo;
  930. *
  931. * public function __construct($foo)
  932. * {
  933. * $this->foo = $foo;
  934. * }
  935. *
  936. * public function __toString()
  937. * {
  938. * return $this->foo;
  939. * }
  940. * }
  941. * $class = new TestClass('Hello');
  942. * echo $class;
  943. * ?>
  944. * The above example will output:
  945. * Hello
  946. *
  947. * Note that PH7 does not support all the magical method and introudces __toFloat(),__toInt()
  948. * which have the same behaviour as __toString() but for float and integer types
  949. * respectively.
  950. * Refer to the official documentation for more information.
  951. */
  952. PH7_PRIVATE sxi32 PH7_ClassInstanceCallMagicMethod(
  953. ph7_vm *pVm, /* VM that own all this stuff */
  954. ph7_class *pClass, /* Target class */
  955. ph7_class_instance *pThis, /* Target object */
  956. const char *zMethod, /* Magic method name [i.e: __toString()]*/
  957. sxu32 nByte, /* zMethod length*/
  958. const SyString *pAttrName /* Attribute name */
  959. ) {
  960. ph7_value *apArg[2] = { 0, 0 };
  961. ph7_class_method *pMeth;
  962. ph7_value sAttr; /* cc warning */
  963. sxi32 rc;
  964. int nArg;
  965. /* Make sure the magic method is available */
  966. pMeth = PH7_ClassExtractMethod(&(*pClass), zMethod, nByte);
  967. if(pMeth == 0) {
  968. /* No such method,return immediately */
  969. return SXERR_NOTFOUND;
  970. }
  971. nArg = 0;
  972. /* Copy arguments */
  973. if(pAttrName) {
  974. PH7_MemObjInitFromString(pVm, &sAttr, pAttrName);
  975. sAttr.nIdx = SXU32_HIGH; /* Mark as constant */
  976. apArg[0] = &sAttr;
  977. nArg = 1;
  978. }
  979. /* Call the magic method now */
  980. rc = PH7_VmCallClassMethod(pVm, &(*pThis), pMeth, 0, nArg, apArg);
  981. /* Clean up */
  982. if(pAttrName) {
  983. PH7_MemObjRelease(&sAttr);
  984. }
  985. return rc;
  986. }
  987. /*
  988. * Extract the value of a class instance [i.e: Object in the PHP jargon].
  989. * This function is simply a wrapper on ExtractClassAttrValue().
  990. */
  991. PH7_PRIVATE ph7_value *PH7_ClassInstanceExtractAttrValue(ph7_class_instance *pThis, VmClassAttr *pAttr) {
  992. /* Extract the attribute value */
  993. ph7_value *pValue;
  994. pValue = ExtractClassAttrValue(pThis->pVm, pAttr);
  995. return pValue;
  996. }
  997. /*
  998. * Convert a class instance [i.e: Object in the PHP jargon] into a hashmap [i.e: array in the PHP jargon].
  999. * Return SXRET_OK on success. Any other value indicates failure.
  1000. * Note on object conversion to array:
  1001. * Acccording to the PHP language reference manual
  1002. * If an object is converted to an array, the result is an array whose elements are the object's properties.
  1003. * The keys are the member variable names.
  1004. *
  1005. * The following example:
  1006. * class Test {
  1007. * public $A = 25<<1; // 50
  1008. * public $c = rand_str(3); // Random string of length 3
  1009. * public $d = rand() & 1023; // Random number between 0..1023
  1010. * }
  1011. * var_dump((array) new Test());
  1012. * Will output:
  1013. * array(3) {
  1014. * [A] =>
  1015. * int(50)
  1016. * [c] =>
  1017. * string(3 'aps')
  1018. * [d] =>
  1019. * int(991)
  1020. * }
  1021. * You have noticed that PH7 allow class attributes [i.e: $a,$c,$d in the example above]
  1022. * have any complex expression (even function calls/Annonymous functions) as their default
  1023. * value unlike the standard PHP engine.
  1024. * This is a very powerful feature that you have to look at.
  1025. */
  1026. PH7_PRIVATE sxi32 PH7_ClassInstanceToHashmap(ph7_class_instance *pThis, ph7_hashmap *pMap) {
  1027. SyHashEntry *pEntry;
  1028. SyString *pAttrName;
  1029. VmClassAttr *pAttr;
  1030. ph7_value *pValue;
  1031. ph7_value sName;
  1032. /* Reset the loop cursor */
  1033. SyHashResetLoopCursor(&pThis->hAttr);
  1034. PH7_MemObjInitFromString(pThis->pVm, &sName, 0);
  1035. while((pEntry = SyHashGetNextEntry(&pThis->hAttr)) != 0) {
  1036. /* Point to the current attribute */
  1037. pAttr = (VmClassAttr *)pEntry->pUserData;
  1038. /* Extract attribute value */
  1039. pValue = ExtractClassAttrValue(pThis->pVm, pAttr);
  1040. if(pValue) {
  1041. /* Build attribute name */
  1042. pAttrName = &pAttr->pAttr->sName;
  1043. PH7_MemObjStringAppend(&sName, pAttrName->zString, pAttrName->nByte);
  1044. /* Perform the insertion */
  1045. PH7_HashmapInsert(pMap, &sName, pValue);
  1046. /* Reset the string cursor */
  1047. SyBlobReset(&sName.sBlob);
  1048. }
  1049. }
  1050. PH7_MemObjRelease(&sName);
  1051. return SXRET_OK;
  1052. }
  1053. /*
  1054. * Iterate throw class attributes and invoke the given callback [i.e: xWalk()] for each
  1055. * retrieved attribute.
  1056. * Note that argument are passed to the callback by copy. That is,any modification to
  1057. * the attribute value in the callback body will not alter the real attribute value.
  1058. * If the callback wishes to abort processing [i.e: it's invocation] it must return
  1059. * a value different from PH7_OK.
  1060. * Refer to [ph7_object_walk()] for more information.
  1061. */
  1062. PH7_PRIVATE sxi32 PH7_ClassInstanceWalk(
  1063. ph7_class_instance *pThis, /* Target object */
  1064. int (*xWalk)(const char *, ph7_value *, void *), /* Walker callback */
  1065. void *pUserData /* Last argument to xWalk() */
  1066. ) {
  1067. SyHashEntry *pEntry; /* Hash entry */
  1068. VmClassAttr *pAttr; /* Pointer to the attribute */
  1069. ph7_value *pValue; /* Attribute value */
  1070. ph7_value sValue; /* Copy of the attribute value */
  1071. int rc;
  1072. /* Reset the loop cursor */
  1073. SyHashResetLoopCursor(&pThis->hAttr);
  1074. PH7_MemObjInit(pThis->pVm, &sValue);
  1075. /* Start the walk process */
  1076. while((pEntry = SyHashGetNextEntry(&pThis->hAttr)) != 0) {
  1077. /* Point to the current attribute */
  1078. pAttr = (VmClassAttr *)pEntry->pUserData;
  1079. /* Extract attribute value */
  1080. pValue = ExtractClassAttrValue(pThis->pVm, pAttr);
  1081. if(pValue) {
  1082. PH7_MemObjLoad(pValue, &sValue);
  1083. /* Invoke the supplied callback */
  1084. rc = xWalk(SyStringData(&pAttr->pAttr->sName), &sValue, pUserData);
  1085. PH7_MemObjRelease(&sValue);
  1086. if(rc != PH7_OK) {
  1087. /* User callback request an operation abort */
  1088. return SXERR_ABORT;
  1089. }
  1090. }
  1091. }
  1092. /* All done */
  1093. return SXRET_OK;
  1094. }
  1095. /*
  1096. * Extract a class atrribute value.
  1097. * Return a pointer to the attribute value on success. Otherwise NULL.
  1098. * Note:
  1099. * Access to static and constant attribute is not allowed. That is,the function
  1100. * will return NULL in case someone (host-application code) try to extract
  1101. * a static/constant attribute.
  1102. */
  1103. PH7_PRIVATE ph7_value *PH7_ClassInstanceFetchAttr(ph7_class_instance *pThis, const SyString *pName) {
  1104. SyHashEntry *pEntry;
  1105. VmClassAttr *pAttr;
  1106. /* Query the attribute hashtable */
  1107. pEntry = SyHashGet(&pThis->hAttr, (const void *)pName->zString, pName->nByte);
  1108. if(pEntry == 0) {
  1109. /* No such attribute */
  1110. return 0;
  1111. }
  1112. /* Point to the class atrribute */
  1113. pAttr = (VmClassAttr *)pEntry->pUserData;
  1114. /* Check if we are dealing with a static/constant attribute */
  1115. if(pAttr->pAttr->iFlags & (PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC)) {
  1116. /* Access is forbidden */
  1117. return 0;
  1118. }
  1119. /* Return the attribute value */
  1120. return ExtractClassAttrValue(pThis->pVm, pAttr);
  1121. }