diff --git src/wp-includes/class-wp-array-object.php src/wp-includes/class-wp-array-object.php
new file mode 100644
index 0000000..9f20b04
--- /dev/null
+++ src/wp-includes/class-wp-array-object.php
@@ -0,0 +1,217 @@
+<?php
+/**
+ * Utility class for implementing array access: WP_Array_Object class.
+ *
+ * @package WordPress
+ * @subpackage WP_Array_Object
+ * @since 4.7.0
+ */
+
+class WP_Array_Object implements Iterator, ArrayAccess {
+	private $data = array();
+
+	/**
+	 * Converts passed data to an array.
+	 * @param String|stdClass|Array $data Data to be made available both using array and class methods.
+	 */
+	function __construct( $data ) {
+		if ( is_object( $data ) ) {
+			$r = get_object_vars( $data );
+		} elseif ( is_string( $data ) ) {
+			wp_parse_str( $data, $r );
+		} else {
+			$r = (array) $data;
+		}
+
+		$this->data = $r;
+	}
+
+	/**
+	 * Gets a specified key
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 *
+	 * @link http://php.net/manual/en/language.oop5.overloading.php#object.get
+	 *
+	 * @param mixed $key The key to get the value for.
+	 */
+	public function &__get( $key ) {
+		return $this->data[ $key ];
+	}
+
+	/**
+	 * Sets a specified key
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 *
+	 * @link http://php.net/manual/en/language.oop5.overloading.php#object.set
+	 *
+	 * @param mixed $key   The key to assign the value to.
+	 * @param mixed $value The value to set.
+	 */
+	public function __set( $key, $value ) {
+		$this->data[ $key ] = $value;
+	}
+
+	/**
+	 * Determines whether a key value exists.
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 *
+	 * @link http://php.net/manual/en/language.oop5.overloading.php#object.isset
+	 *
+	 * @param mixed $key A key to check for.
+	 * @return bool True if the key exists, false otherwise.
+	 */
+	public function __isset( $key ) {
+		return isset( $this->data[ $key ] );
+	}
+
+	/**
+	 * Unsets a specified key
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 *
+	 * @link http://php.net/manual/en/language.oop5.overloading.php#object.unset
+	 *
+	 * @param mixed $key The key to unset.
+	 */
+	public function __unset( $key ) {
+		unset( $this->data[ $key ] );
+	}
+
+	/**
+	 * Sets a value at a specified offset.
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 *
+	 * @link http://php.net/manual/en/arrayaccess.offsetset.php
+	 *
+	 * @param mixed $offset The offset to assign the value to.
+	 * @param mixed $value The value to set.
+	 */
+	public function offsetSet( $offset, $value ) {
+		if ( is_null( $offset ) ) {
+			$this->data[] = $value;
+		} else {
+			$this->data[ $offset ] = $value;
+		}
+	}
+
+	/**
+	 * Determines whether an offset value exists.
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 *
+	 * @link http://php.net/manual/en/arrayaccess.offsetexists.php
+	 *
+	 * @param mixed $offset An offset to check for.
+	 * @return bool True if the offset exists, false otherwise.
+	 */
+	public function offsetExists( $offset ) {
+		return isset( $this->data[ $offset ] );
+	}
+
+	/**
+	 * Unsets a specified offset.
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 *
+	 * @link http://php.net/manual/en/arrayaccess.offsetunset.php
+	 *
+	 * @param mixed $offset The offset to unset.
+	 */
+	public function offsetUnset( $offset ) {
+		unset( $this->data[ $offset ] );
+	}
+
+	/**
+	 * Retrieves a value at a specified offset.
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 *
+	 * @link http://php.net/manual/en/arrayaccess.offsetget.php
+	 *
+	 * @param mixed $offset The offset to retrieve.
+	 * @return mixed If set, the value at the specified offset, null otherwise.
+	 */
+	public function offsetGet( $offset ) {
+		return isset( $this->data[ $offset ] ) ? $this->data[ $offset ] : null;
+	}
+
+	/**
+	 * Returns the current element.
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 *
+	 * @link http://php.net/manual/en/iterator.current.php
+	 *
+	 * @return array Of callbacks at current priority.
+	 */
+	public function current() {
+		return current( $this->data );
+	}
+
+	/**
+	 * Moves forward to the next element.
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 *
+	 * @link http://php.net/manual/en/iterator.next.php
+	 *
+	 * @return array Of callbacks at next priority.
+	 */
+	public function next() {
+		return next( $this->data );
+	}
+
+	/**
+	 * Returns the key of the current element.
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 *
+	 * @link http://php.net/manual/en/iterator.key.php
+	 *
+	 * @return mixed Returns current priority on success, or NULL on failure
+	 */
+	public function key() {
+		return key( $this->data );
+	}
+
+	/**
+	 * Checks if current position is valid.
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 *
+	 * @link http://php.net/manual/en/iterator.valid.php
+	 *
+	 * @return boolean
+	 */
+	public function valid() {
+		return key( $this->data ) !== null;
+	}
+
+	/**
+	 * Rewinds the Iterator to the first element.
+	 *
+	 * @since 4.7.0
+	 * @access public
+	 *
+	 * @link http://php.net/manual/en/iterator.rewind.php
+	 */
+	public function rewind() {
+		reset( $this->data );
+	}
+}
diff --git src/wp-settings.php src/wp-settings.php
index 6ff4ab4..f46cf5b 100644
--- src/wp-settings.php
+++ src/wp-settings.php
@@ -218,6 +218,7 @@ require( ABSPATH . WPINC . '/rest-api.php' );
 require( ABSPATH . WPINC . '/rest-api/class-wp-rest-server.php' );
 require( ABSPATH . WPINC . '/rest-api/class-wp-rest-response.php' );
 require( ABSPATH . WPINC . '/rest-api/class-wp-rest-request.php' );
+require( ABSPATH . WPINC . '/class-wp-array-object.php' );
 
 $GLOBALS['wp_embed'] = new WP_Embed();
 
diff --git tests/phpunit/tests/array-object.php tests/phpunit/tests/array-object.php
new file mode 100644
index 0000000..bf8f563
--- /dev/null
+++ tests/phpunit/tests/array-object.php
@@ -0,0 +1,121 @@
+<?php
+
+/**
+ * Test access array helper class.
+ */
+class Tests_ArrayObject extends WP_UnitTestCase {
+
+	private $test_data = array();
+	private $array_object;
+
+	public function setUp() {
+		parent::setUp();
+		$this->test_data = array(
+			'pens'    => 'pencils',
+			'puppies' => 'kittens',
+			'array'   => 'object',
+			'args'    => 'array',
+		);
+
+		$this->array_object = new WP_Array_Object( $this->test_data );
+	}
+
+	function test_data_matches() {
+		$r = $this->array_object;
+
+		$this->assertEquals( $r->pens, $r['pens'] );
+		$this->assertEquals( $r->puppies, $r['puppies'] );
+		$this->assertEquals( $r->array, $r['array'] );
+		$this->assertEquals( $r->args, $r['args'] );
+	}
+
+	function test_isset_data() {
+		$r = $this->array_object;
+
+		// Check unset data.
+		$this->assertFalse( isset( $r->empty ) );
+		$this->assertFalse( isset( $r['empty'] ) );
+
+		// Check set data.
+		$this->assertTrue( isset( $r->pens ) );
+		$this->assertTrue( isset( $r['pens'] ) );
+	}
+
+	function test_adding_data() {
+		$r = new WP_Array_Object( array() );
+
+		$r['dock'] = 'yards';
+		$r->shipping = 'channel';
+
+		$this->assertEquals( $r->dock, 'yards' );
+		$this->assertEquals( $r['shipping'], 'channel' );
+	}
+
+	function test_unsetting_data() {
+		$r = new WP_Array_Object( array(
+			'shipping' => 'container',
+			'runner'   => 'with dog',
+			'empty'    => 'truck',
+		) );
+
+		unset( $r->shipping );
+		unset( $r['runner'] );
+
+		$this->assertFalse( isset( $r->shipping ) );
+		$this->assertFalse( isset( $r['shipping'] ) );
+		$this->assertFalse( isset( $r->runner ) );
+		$this->assertFalse( isset( $r['runner'] ) );
+	}
+
+	function test_new_class_from_object() {
+		$object = (object) array(
+			'bowl'   => 'white',
+			'orange' => 'orange',
+			'lemon'  => 'yellow',
+		);
+
+		$r = new WP_Array_Object( $object );
+
+		$this->assertInstanceOf( 'stdClass', $object );
+		$this->assertInstanceOf( 'WP_Array_Object', $r );
+		$this->assertEquals( $r['bowl'], $r->bowl );
+	}
+
+	function test_new_class_from_array() {
+		$array = array(
+			'bowl'   => 'white',
+			'orange' => 'orange',
+			'lemon'  => 'yellow',
+		);
+
+		$r = new WP_Array_Object( $array );
+
+		$this->assertTrue( is_array( $array ) );
+		$this->assertInstanceOf( 'WP_Array_Object', $r );
+		$this->assertEquals( $r['bowl'], $r->bowl );
+	}
+
+	function test_trigger_error_with_unset_value() {
+		$r = $this->array_object;
+
+		$this->assertEquals( null, $r['bowl'] );
+		$this->assertEquals( null, $r->bowl );
+	}
+
+	function test_foreach_loop() {
+		$r = $this->array_object;
+		$keys = array();
+		$vals = array();
+
+		$keys_expected = array( 'pens', 'puppies', 'array', 'args' );
+		$vals_expected = array( 'pencils', 'kittens', 'object', 'array' );
+
+		foreach ( $r as $key => $value ) {
+			$keys[] = $key;
+			$vals[] = $value;
+		}
+
+		$this->assertEquals( $keys_expected, $keys );
+		$this->assertEquals( $vals_expected, $vals );
+	}
+}
