/** * Returns an array of all objects referenced either * directly or indirectly by a variable. * * @param array|object $variable * * @return object[] */ public function enumerate($variable) { if (!is_array($variable) && !is_object($variable)) { throw new InvalidArgumentException(); } if (isset(func_get_args()[1])) { if (!func_get_args()[1] instanceof Context) { throw new InvalidArgumentException(); } $processed = func_get_args()[1]; } else { $processed = new Context(); } $objects = []; if ($processed->contains($variable)) { return $objects; } $array = $variable; $processed->add($variable); if (is_array($variable)) { foreach ($array as $element) { if (!is_array($element) && !is_object($element)) { continue; } $objects = array_merge($objects, $this->enumerate($element, $processed)); } } else { $objects[] = $variable; $reflector = new \ReflectionObject($variable); foreach ($reflector->getProperties() as $attribute) { $attribute->setAccessible(true); $value = $attribute->getValue($variable); if (!is_array($value) && !is_object($value)) { continue; } $objects = array_merge($objects, $this->enumerate($value, $processed)); } } return $objects; }
/** * @param mixed $data The data to export as a string * @param SebastianBergmann\RecursionContext\Context $processed Contains all objects and arrays that have previously been processed * @return string * @since Method available since Release 3.2.1 */ protected function dataToString(&$data, $processed = null) { $result = array(); $exporter = new Exporter(); if (!$processed) { $processed = new Context(); } $processed->add($data); foreach ($data as $key => $value) { if (is_array($value)) { if ($processed->contains($data[$key]) !== false) { $result[] = '*RECURSION*'; } else { $result[] = sprintf('array(%s)', $this->dataToString($data[$key], $processed)); } } else { $result[] = $exporter->shortenedExport($value); } } return join(', ', $result); }
/** * Recursive implementation of export * * @param mixed $value The value to export * @param int $indentation The indentation level of the 2nd+ line * @param \SebastianBergmann\RecursionContext\Context $processed Previously processed objects * @return string * @see SebastianBergmann\Exporter\Exporter::export */ protected static function recursiveExport(&$value, $indentation, $processed = null) { if ($value === null) { return 'null'; } if ($value === true) { return 'true'; } if ($value === false) { return 'false'; } if (is_float($value) && floatval(intval($value)) === $value) { return "{$value}.0"; } if (is_resource($value)) { return sprintf('resource(%d) of type (%s)', $value, get_resource_type($value)); } if (is_string($value)) { // Match for most non printable chars somewhat taking multibyte chars into account if (preg_match('/[^\\x09-\\x0d\\x20-\\xff]/', $value)) { return 'Binary String: 0x' . bin2hex($value); } return "'" . str_replace(array("\r\n", "\n\r", "\r"), array("\n", "\n", "\n"), $value) . "'"; } $whitespace = str_repeat(' ', 4 * $indentation); if (!$processed) { $processed = new Context(); } if (is_array($value)) { if (($key = $processed->contains($value)) !== false) { return 'Array &' . $key; } $array = $value; $key = $processed->add($value); $values = ''; if (count($array) > 0) { foreach ($array as $k => $v) { $values .= sprintf('%s %s => %s' . "\n", $whitespace, self::recursiveExport($k, $indentation), self::recursiveExport($value[$k], $indentation + 1, $processed)); } $values = "\n" . $values . $whitespace; } return sprintf('Array &%s (%s)', $key, $values); } if (is_object($value)) { $class = get_class($value); if ($value instanceof ProphecyInterface) { return sprintf('%s Object (*Prophecy*)', $class); } elseif ($hash = $processed->contains($value)) { return sprintf('%s:%s Object', $class, $hash); } $hash = $processed->add($value); $values = ''; $array = self::toArray($value); if (count($array) > 0) { foreach ($array as $k => $v) { $values .= sprintf('%s %s => %s' . "\n", $whitespace, self::recursiveExport($k, $indentation), self::recursiveExport($v, $indentation + 1, $processed)); } $values = "\n" . $values . $whitespace; } return sprintf('%s:%s Object (%s)', $class, $hash, $values); } return var_export($value, true); }
/** * @covers SebastianBergmann\RecursionContext\Context::contains * @dataProvider valuesProvider */ public function testContainsNotFound($value) { $this->assertFalse($this->context->contains($value)); }