Thursday, August 5, 2010

Capturing Variable Type Data By Running PHP

PHP is hard to automatically convert to other languages because there is little type information hardcoded into it. Here's some sample code that uses the debug interface to extract type information out for variables. For now, it just dumps the type data to stdout. Presumably you would need to save this to some sort of sqlite database and run all of your automated tests to ensure full code coverage. Then you could translate your parsed PHP to another language with the additional information known.

// Use xdebug to determine type information about all of the executed parts of your script
// to run, 1: execute this
// 2: export XDEBUG_CONFIG="idekey=session_name remote_autostart=1 remote_host= remote_enable=1"
// 3: run your cli php script

// Set time limit to indefinite execution
set_time_limit (0);

// Set the ip and port we will listen on
$address = '';
$port = 9000;

// Create a TCP Stream socket
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
// Bind the socket to an address/port
socket_bind($sock, $address, $port) or die('Could not bind to address');
// Start listening for connections

/* Accept incoming requests and handle them as child processes */
$client = socket_accept($sock);

// Read the input from the client – 1024 bytes
$input = socket_read($client, 1024);
// Strip all white spaces from input
$output = preg_replace("/[ \t\n\r]/","",$input).chr(0);
$doc = new DOMDocument();
function read_debugger()
global $client;
$string = '';
$char = socket_read($client, 1);
while(! socket_error() && $char <> "\0") {
$string .= $char;
$char = socket_read($client, 1);
return $string;
while(! socket_last_error($client)) {
socket_write($client, "step_into -i ".$i."\0");
$file_line_info = socket_read($client, 1024);
preg_match('/filename="(.*?)"/', $file_line_info, $matches);
$line_no = $matches[1];
preg_match('/lineno="(.*?)"/', $file_line_info, $matches);
$filename = $matches[1];
echo("$filename : $line_no ");
socket_write($client, "context_get -i ".$i."\0");
$dummy = read_debugger();
$context_info = read_debugger();

if (!($doc->loadXML($context_info))) {
die("FAIL ON ".$context_info);
$propertyNodes = $doc->getElementsByTagName('property');
for($j = 0; $j < $propertyNodes->length; $j++) {
$property = $propertyNodes->item($j);
echo($property->getAttribute('fullname').':'.$property->getAttribute('type').' ');

// Close the client (child) socket

// Close the master sockets