diff --git a/src/parser/PhutilJSON.php b/src/parser/PhutilJSON.php
--- a/src/parser/PhutilJSON.php
+++ b/src/parser/PhutilJSON.php
@@ -19,7 +19,7 @@
    * @param   dict    An object to encode in JSON.
    * @return  string  Pretty-printed object representation.
    */
-  public function encodeFormatted(array $object) {
+  public function encodeFormatted($object) {
     return $this->encodeFormattedObject($object, 0)."\n";
   }
 
@@ -47,6 +47,10 @@
    * @task internal
    */
   private function encodeFormattedObject($object, $depth) {
+    if ($object instanceof stdClass) {
+      $object = (array)$object;
+    }
+
     if (empty($object)) {
       return '{}';
     }
@@ -123,6 +127,8 @@
       } else {
         return $this->encodeFormattedObject($value, $depth);
       }
+    } else if (is_object($value)) {
+      return $this->encodeFormattedObject($value, $depth);
     } else {
       if (defined('JSON_UNESCAPED_SLASHES')) {
         // If we have a new enough version of PHP, disable escaping of slashes
diff --git a/src/parser/__tests__/PhutilJSONTestCase.php b/src/parser/__tests__/PhutilJSONTestCase.php
--- a/src/parser/__tests__/PhutilJSONTestCase.php
+++ b/src/parser/__tests__/PhutilJSONTestCase.php
@@ -18,4 +18,33 @@
       pht('Empty arrays should serialize as `%s`, not `%s`.', '[]', '{}'));
   }
 
+  public function testNestedObjectEncoding() {
+    $expect = <<<EOJSON
+{
+  "empty-object": {},
+  "pair-object": {
+    "duck": "quack"
+  }
+}
+
+EOJSON;
+
+    $empty_object = new stdClass();
+
+    $pair_object = new stdClass();
+    $pair_object->duck = 'quack';
+
+    $input = (object)array(
+      'empty-object' => $empty_object,
+      'pair-object' => $pair_object,
+    );
+
+    $serializer = new PhutilJSON();
+
+    $this->assertEqual(
+      $expect,
+      $serializer->encodeFormatted($input),
+      pht('Serialization of PHP-object JSON values.'));
+  }
+
 }