/**
  * 
  * @dataProvider writeInstantiationDataProvider
  * @param string $expected
  * @param string $classname
  * @param PhpArgumentCollection $arguments
  */
 public function testWriteInstantiation($expected, $classname, PhpArgumentCollection $arguments = null)
 {
     $access = new PhpStreamAccess($this->getStream());
     $access->writeInstantiation($classname, $arguments);
     $this->assertEquals($expected, $this->getStream()->getBinary());
 }
 /**
  * Save the PhpDocument to a specific location.
  * 
  * @param string $url A URL (Uniform Resource Locator) describing where to save the document.
  * @throws PhpStorageException If an error occurs while saving.
  */
 public function save($url)
 {
     $stack = new SplStack();
     $stack->push($this->getDocumentComponent());
     // 1st/2nd pass marker.
     $marker = array();
     try {
         // marshalling context.
         $stream = new MemoryStream();
         $stream->open();
         $streamAccess = new PhpStreamAccess($stream);
         $streamAccess->writeOpeningTag();
         $ctx = new PhpMarshallingContext($streamAccess);
         $ctx->setFormatOutput(true);
         while (count($stack) > 0) {
             $component = $stack->pop();
             $isMarked = in_array($component, $marker, true);
             if ($isMarked === false && $component instanceof QtiComponent) {
                 // -- QtiComponent node, 1st pass.
                 // Mark as explored.
                 array_push($marker, $component);
                 // Ask for a 2nd pass.
                 $stack->push($component);
                 // Let's look at the Bean properties and ask for a future exploration.
                 $bean = new Bean($component, false, self::getBaseImplementation($component));
                 $ctorGetters = $bean->getConstructorGetters();
                 $bodyGetters = $bean->getGetters(true);
                 $getters = array_reverse(array_merge($bodyGetters->getArrayCopy(), $ctorGetters->getArrayCopy()));
                 foreach ($getters as $getter) {
                     $stack->push(call_user_func(array($component, $getter->getName())));
                 }
             } else {
                 if ($isMarked === false && ($component instanceof AbstractCollection && !$component instanceof Coords)) {
                     // AbstractCollection node, 1st pass.
                     // Mark as explored.
                     array_push($marker, $component);
                     // Ask for a 2nd pass.
                     $stack->push($component);
                     // Explore all values of the collection please!
                     $values = array_reverse($component->getArrayCopy());
                     foreach ($values as $val) {
                         $stack->push($val);
                     }
                 } else {
                     if ($isMarked === true && $component instanceof QtiComponent) {
                         // QtiComponent, 2nd pass.
                         $marshaller = new PhpQtiComponentMarshaller($ctx, $component);
                         $marshaller->setAsInstanceOf(self::getBaseImplementation($component));
                         if ($component === $this->getDocumentComponent()) {
                             $marshaller->setVariableName('rootcomponent');
                         }
                         $marshaller->marshall();
                     } else {
                         if ($component instanceof QtiDatatype) {
                             // Leaf node QtiDataType.
                             $marshaller = new PhpQtiDatatypeMarshaller($ctx, $component);
                             $marshaller->marshall();
                         } else {
                             if ($isMarked === true && $component instanceof AbstractCollection) {
                                 // AbstractCollection, 2nd pass.
                                 $marshaller = new PhpCollectionMarshaller($ctx, $component);
                                 $marshaller->marshall();
                             } else {
                                 if (PhpUtils::isScalar($component) === true) {
                                     // Leaf node (QtiDatatype or PHP scalar (including the null value)).
                                     $marshaller = new PhpScalarMarshaller($ctx, $component);
                                     $marshaller->marshall();
                                 } else {
                                     if (is_array($component) === true) {
                                         // Leaf node array.
                                         $marshaller = new PhpArrayMarshaller($ctx, $component);
                                         $marshaller->marshall();
                                     } else {
                                         $msg = "Datatype '" . gettype($component) . "' cannot be handled by the PhpDocument::save() method.";
                                         throw new PhpStorageException($msg);
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
         file_put_contents($url, $stream->getBinary());
     } catch (StreamAccessException $e) {
         $msg = "An error occured while writing the PHP source code stream.";
         throw new PhpStorageException($msg, 0, $e);
     }
 }