Since I got the basic sanity checking PHP script running without crashing, there was one problem remaining around MgByteReader contents being read incorrectly. This turned out to be another out-of-date SWIG typemap around byte arrays. Once that got fixed we are able to read out the contents of the MgByteReader without content corruption. This is an important thing to test because a lot of results from the MapGuide API (XML results, rendered map images, map plots, etc) come in the form of MgByteReaders. If we can't read content out of these readers without data corruption we have major problems, but that is fortunately not the case (so far!).
With that out of the way, it was onto to the current PHP test suite for the MapGuide API and getting it fixed up and passing.
But before we go there, I wanted to check if our new PHP binding was leaking memory in the most obvious cases. To that effect, I built our PHP binding with reference counting diagnostics enabled and wrote this PHP script.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | <?php function exceptionTest() { /* Expected release book-keeping: MgException - 1 */ try { $rid = new MgResourceIdentifier("iamnotvalid"); } catch (MgException $ex) { } } function throwingFunction() { $agfRw = new MgAgfReaderWriter(); $wktRw = new MgWktReaderWriter(); $rid = new MgResourceIdentifier("iamnotvalid"); } function exceptionTest2() { /* Expected release book-keeping: MgAgfReaderWriter - 1 MgWktReaderWriter - 1 MgException - 1 */ try { throwingFunction(); } catch (MgException $ex) { } } function exceptionTest3() { /* Expected release book-keeping: MgAgfReaderWriter - 1 MgWktReaderWriter - 1 MgException - 2 */ try { $rid = new MgResourceIdentifier("iamnotvalid"); } catch (MgException $ex) { } try { throwingFunction(); } catch (MgException $ex) { //Previous iterations of the binding would leak the previous $ex when //reusing the variable in this catch block //If the release book-keeping for MgException is 2, then this is no //longer the case } } function geometryXformTest() { /* Expected release book-keeping: MgCoordinateSystemFactory - 1 MgCoordinateSystem - 2 MgTransform - 1 MgWktReaderWriter - 1 MgPoint - 2 MgCoordinateXY - 2 */ $csFactory = new MgCoordinateSystemFactory(); $cs1 = $csFactory->CreateFromCode("LL84"); $cs2 = $csFactory->CreateFromCode("WGS84.PseudoMercator"); $xform = $csFactory->GetTransform($cs1, $cs2); $wktRw = new MgWktReaderWriter(); $pt = $wktRw->Read("POINT (1 2)"); $coord = $pt->GetCoordinate(); echo "Point (".$coord->GetX().", ".$coord->GetY().")\n"; $pt = $pt->Transform($xform); $coord = $pt->GetCoordinate(); echo "XPoint (".$coord->GetX().", ".$coord->GetY().")\n"; } function connectionServiceTest() { /* Expected release book-keeping: MgUserInformation - 1 MgSiteConnection - 1 MgProxyResourceService - 1 MgProxyFeatureService - 1 MgProxyRenderingService - 1 MgProxyMappingService - 1 MgProxyKmlService - 1 MgProxyDrawingService - 1 MgProxyTileService - 1 MgProxyProfilingService - 1 */ $userInfo = new MgUserInformation("Anonymous", ""); $site = new MgSiteConnection(); $site->Open($userInfo); $service1 = $site->CreateService(MgServiceType::ResourceService); $service2 = $site->CreateService(MgServiceType::FeatureService); $service3 = $site->CreateService(MgServiceType::RenderingService); $service4 = $site->CreateService(MgServiceType::MappingService); $service5 = $site->CreateService(MgServiceType::KmlService); $service6 = $site->CreateService(MgServiceType::DrawingService); $service7 = $site->CreateService(MgServiceType::TileService); $service8 = $site->CreateService(MgServiceType::ProfilingService); } function functionWithParam($userInfo) { $userInfo->SetLocale("en"); } function parameterPassingTest() { // We want to check parameters of Mg* objects passed do not encounter // refcounting shenanigans, but if they do, we want to make sure that // proper increment/decrement is happening so that the MgUserInformation // is released to 0 refcount (and thus deleted) when this function returns /* Expected release book-keeping: MgUserInformation - 1 */ $userInfo = new MgUserInformation(); functionWithParam($userInfo); echo "Locale: " . $userInfo->GetLocale() . "\n"; } MgInitializeWebTier("C:\\mg-4.0-install\\Web\\www\\webconfig_dev.ini"); echo "=========== BEGIN - exceptionTest() ===========\n"; exceptionTest(); echo "=========== END - exceptionTest() ===========\n"; echo "=========== BEGIN - exceptionTest2() ===========\n"; exceptionTest2(); echo "=========== END - exceptionTest2() ===========\n"; echo "=========== BEGIN - exceptionTest3() ===========\n"; exceptionTest3(); echo "=========== END - exceptionTest3() ===========\n"; echo "=========== BEGIN - connectionServiceTest() ===========\n"; connectionServiceTest(); echo "=========== END - connectionServiceTest() ===========\n"; echo "=========== BEGIN - parameterPassingTest() ===========\n"; parameterPassingTest(); echo "=========== END - parameterPassingTest() ===========\n"; echo "=========== BEGIN - geometryXformTest() ===========\n"; geometryXformTest(); echo "=========== END - geometryXformTest() ===========\n"; ?> |
- If we new any Mg* class, we expect it to be released (reference count dropped by 1) once the respective variable goes out of scope. We consider the script to not be leaking if every "new" statement has a corresponding release as reported by our refcounting diagnostics.
- Any non-primitive value returned by any class in the MapGuide API is also released once its respective captured variable goes out of scope
- If an MgException is thrown and we catch it, it is released once we exit the respective catch block
- If we have multiple try/catch blocks on MgException and we use the same variable name for the caught exception, we're not leaking on subsequent catch blocks (this used to happen when we were generating the PHP bindings on the older SWIG/PHP version)
- Finally any MapGuide API object passed as parameters to other functions does not get touched by reference counting. But if it does, we expect that the reference count for that object is the same before and after the function call.
1 2 | xdebug.mode = debug xdebug.start_with_request = yes |