Randomness Daryl Ducharme Randomness Daryl Ducharme

AMFPHP $_explicitType understood

I've been using AMFPHP for a while now. Up until recently I have been using dumb objects and simple NetConnections to pass things back and forth between Flex and PHP. Over time, the objects I was passing back and forth got more complex and strong typing of the objects looked like a better way to go, but there was a lot of code that would have to change in my libraries to make it happen so I kept putting it off. ...

Recently, a couple projects I was working on had me take a look at the Cairngorm micro-architecture to help speed up (re)development. After finding some great tutorials on getting starting with Cairngorm I decided it fit the bill for my needs.

Cairngorm would allow me to refactor some basic frameworks I was going to use for these and future projects while allowing for easier customization and modification. The architecture makes use of RemoteObjects to pass data back and forth instead of raw NetConnection objects. Between RemoteObjects and the ValueObject design (anti?)pattern I felt it was time to work on strong typing my variables, specifically the ones traveling from PHP to Flex.

Two important parts to making this work are the RemoteClass meta tag in Flex and the $_explicitType variable in PHP. The RemoteClass meta tag lets your application know the fully qualified name of an alias class on your server. It works the same for AMFPHP, ColdFusion, Java and others. It should look something like this:

package path.to.asClasses
{
  [RemoteClass(alias="path.to.MyAliasClass")]
  public class MyASClass
  {
    public var id:uint;
    public var name:String;
  }
}

My first thought about the $_explicit type variable was that it would be the inverse of the RemoteClass meta tag and point to the actionscript class. With that in mind I wrote something like this:

<?php

class MyAliasClass
{
  var $_explicitType = "path.to.asClasses.MyASClass";

  var $id;
  var $name;

  public function MyAliasClass( ){}
}

?>

Unfortunately, the data that got passed back to Flex was typed as an ObjectProxy object instead of as a MyASClass object as intended. I did all the basic troubleshooting. I made sure everything was spelled the same. I tried to do searches online and got mostly references passing VOs from Flex to PHP and/or Patrick Mineaults opinion that doing so is wasteful. Not many of the search results talked about going from PHP to Flex and those that did just said you needed to use $_explicitType. Unfortunately I can't find the posting again, but I came across a short post that said they had a similar problem and got it to work by changing $_explicitType to a string representing the fully qualified path of the PHP class. He didn't know why it worked, and neither did I, but I tried the following code and class typing occured as expected:

<?php

class MyAliasClass
{
  var $_explicitType = "path.to.MyAliasClass";

  var $id;
  var $name;

  public function MyAliasClass( ){}
}

?>

As usual, I got it working and now I needed to understand why. Not only why did it work but why did they use the term explicit type? It turns out the use of the RemoteClass meta tag takes care of mapping in both directions. When the Flex app encounters an alias object from remoting ( in this case path.to.MyAliasClass ) it knows what AS class is equivalent. As for explicitType, you just have to think about the full notation ( MyAliasClass::_explicitType ). In object oriented languages an object's properties should represent it's state. In this case it represents the explicit type of MyAliasClass. This is required due to the constraints of PHP. PHP is not case sensitive when it comes to class names. Also, PHP doesn't actually use classpaths. When you include a file there is no reference to the directory structure passed along with it. Though one could be derived, it isn't built into AMFPHP natively.

--
Some other good news related to AMFPHP. While looking for answers I see that AMFPHP now has a new lead who is working on getting version 2.0 out and ready to go. Supposedly he already got authentication working again. His name is Wade Arnold from T8Design. This is good news as it once again assured the future of the AMFPHP project.

----
Daryl "Deacon" Ducharme is currently Director of Application Development for the Interactive Agency Provis Media Group, LLC which helps organizations enhance identity, connect with customers and increase productivity.

Read More
Randomness Daryl Ducharme Randomness Daryl Ducharme

Headers already sent?!

In my experience, the most annoying and hard to track down bugs are the simplest things. Sometimes you misspell a word. Sometimes you accidentally check for a boolean true when you should be checking for false. The worst are misplaced spaces, tabs, carriage returns and other whitespace that makes an bug hard to track down. ...

What I was trying to do was simple. I just needed to add a class file into my PHP code for an application I am working on. After I added the class file like so:

require_once( "../../../fileDirectory/my_necessary_class.php" );

I started to get errors.

Because this was a Flex application using AMFPHP, my first error popped up in the service browser.

TypeError: Error #1009: Cannot access a property or method of a null object reference.	at RawAmfService/internal::readData()
	at flash.events::EventDispatcher/flash.events:EventDispatcher::dispatchEventFunction()
	at flash.events::EventDispatcher/dispatchEvent()
	at flash.net::URLLoader/flash.net:URLLoader::onComplete()
	at [io]

Ack! Near useless errors, at least it looked like the AMF reading abilities of the flash player were being confounded by whatever they were getting sent. From what eventually came up in the Service Browser's results window I had a bit more information to work with:

(Object)#0
  message = "faultCode:INVALID_AMF_MESSAGE faultString:'Invalid AMF message' faultDetail:'

Warning: Cannot modify header information - headers already sent by (output started at /a/long/path/to/a/site/root/fileDirectory/my_necessary_class.php:464) in /a/long/path/to/a/site/root/amfphp/core/shared/exception/php4Exception.php on line 38
'"
  name = "Error"
  rootCause = (null)

Eureka! proper AMF file headers were not able to be sent because, headers were already sent before the call to send AMF headers.

My deductive process to find the error went like this:
1. Perhaps the file isn't where I think it is. I change the require_once code a little and get an error that tells me that I had it right before.
2. Look for any obvious errors in the class - it works in other programs so I wasn't counting on this to work out for me. It didn't.
3. So that I could edit the class without breaking other applications I made a copy in the same directory and to see if somehow tha was affecting the headers. Still a no go.
4. Finally I decided to comment the entire file out and try it. Success! Slowly I uncommented function by function. In the end I uncommented every function and it still worked.

Not being one to fix a bug without understanding it I did a comparison of the original file and my new version. The only difference was my new version did not have an extra line after the closing ?>. When I saw that I remembered something I read about the PHP include functions( include, include_once, require and require_once ).

When a file is included, parsing drops out of PHP mode and into HTML mode at the beginning of the target file, and resumes again at the end. For this reason, any code inside the target file which should be executed as PHP code must be enclosed within valid PHP start and end tags.

What was happening was that the last line of that file was being sent as HTML, so PHP sent regular HTML headers when the file was included and before the AMF headers were sent. So if you are trying to output non-HTML and your run into a problem where the wrong headers are being sent, check to see if you have some extra whitespace outside of your <?php ?> tags.

----
Daryl "Deacon" Ducharme is currently Director of Application Development for the Interactive Agency Provis Media Group, LLC which helps organizations enhance identity, connect with customers and increase productivity.

Read More