public function render_tags( array $data_sources ) {

		$replaced = array();

		foreach ( $this->get_listeners() as $tag => $listener ) {

			$params = $listener->get_callback_reflection()->getParameters();

			$args = array();

			foreach ( $params as $param ) {

				$found = false;

				foreach ( $data_sources as $name => $data_source ) {

					if ( is_object( $data_source ) && ( $class = $param->getClass() ) !== null && $class->isInstance( $data_source ) ) {
						$args[] = $data_source;
						$found  = true;
					} elseif ( $param->getName() === $name ) {

						if ( isset( $class ) ) {
							throw new \BadMethodCallException(
								"Data source '$name' does not match type of required parameter '{$param->getName()}'. Required type: '{$class->getName()}''",
								1
							);
						}

						$args[] = $data_source;
						$found  = true;
					}

					if ( $found ) {
						break;
					}
				}

				if ( $found ) {
					continue;
				}

				if ( $param->isDefaultValueAvailable() ) {
					$args[] = $param->getDefaultValue();
				} else {
					throw new \BadMethodCallException( "Not all required parameters were provided. Required: '{$param->getName()}'.'", 2 );
				}
			}

			$replaced[ $tag ] = $listener->render( $args );
		}

		return $replaced;
	}