Skip to content

Commit

Permalink
Add path to failure in exception messages
Browse files Browse the repository at this point in the history
  • Loading branch information
BenMorel committed Apr 7, 2019
1 parent df41470 commit c71662b
Show file tree
Hide file tree
Showing 9 changed files with 55 additions and 28 deletions.
12 changes: 12 additions & 0 deletions src/ExportException.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,16 @@

final class ExportException extends \Exception
{
/**
* @param string $message
* @param string[] $path
*/
public function __construct(string $message, array $path)
{
if ($path) {
$message = '[' . implode('][', $path) . '] ' . $message;
}

parent::__construct($message);
}
}
30 changes: 18 additions & 12 deletions src/Internal/GenericExporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,14 @@ public function __construct(int $options)
}

/**
* @param mixed $var The variable to export.
* @param mixed $var The variable to export.
* @param string[] $path The path to the current variable in the array/object graph.
*
* @return string[] The lines of code.
*
* @throws ExportException
*/
public function export($var) : array
public function export($var, array $path = []) : array
{
switch ($type = gettype($var)) {
case 'boolean':
Expand All @@ -74,25 +75,26 @@ public function export($var) : array
return ['null'];

case 'array':
return $this->exportArray($var);
return $this->exportArray($var, $path);

case 'object':
return $this->exportObject($var);
return $this->exportObject($var, $path);

default:
// resources
throw new ExportException(sprintf('Type "%s" is not supported.', $type));
throw new ExportException(sprintf('Type "%s" is not supported.', $type), $path);
}
}

/**
* @param array $array The array to export.
* @param array $array The array to export.
* @param string[] $path The path to the current array in the array/object graph.
*
* @return string[] The lines of code.
*
* @throws ExportException
*/
public function exportArray(array $array) : array
public function exportArray(array $array, array $path = []) : array
{
if (! $array) {
return ['[]'];
Expand All @@ -110,7 +112,10 @@ public function exportArray(array $array) : array
foreach ($array as $key => $value) {
$isLast = (++$current === $count);

$exported = $this->export($value);
$newPath = $path;
$newPath[] = $key;

$exported = $this->export($value, $newPath);

$prepend = '';
$append = '';
Expand All @@ -135,27 +140,28 @@ public function exportArray(array $array) : array
}

/**
* @param object $object The object to export.
* @param object $object The object to export.
* @param string[] $path The path to the current object in the array/object graph.
*
* @return string[] The lines of code.
*
* @throws ExportException
*/
public function exportObject($object) : array
public function exportObject($object, array $path = []) : array
{
$reflectionObject = new \ReflectionObject($object);

foreach ($this->objectExporters as $objectExporter) {
if ($objectExporter->supports($reflectionObject)) {
return $objectExporter->export($object, $reflectionObject);
return $objectExporter->export($object, $reflectionObject, $path);
}
}

// This may only happen when an option is given to disallow specific export methods.

$className = $reflectionObject->getName();

throw new ExportException('Class "' . $className . '" cannot be exported using the current options.');
throw new ExportException('Class "' . $className . '" cannot be exported using the current options.', $path);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/Internal/ObjectExporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@ abstract public function supports(\ReflectionObject $reflectionObject) : bool;
*
* @param object $object The object to export.
* @param \ReflectionObject $reflectionObject A reflection of the object.
* @param string[] $path The path to the current object in the array/object graph.
*
* @return string[] The lines of code.
*
* @throws ExportException
*/
abstract public function export($object, \ReflectionObject $reflectionObject) : array;
abstract public function export($object, \ReflectionObject $reflectionObject, array $path) : array;

/**
* Returns the code to create a new object of the given class.
Expand Down
12 changes: 9 additions & 3 deletions src/Internal/ObjectExporter/AnyObjectExporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function supports(\ReflectionObject $reflectionObject) : bool
/**
* {@inheritDoc}
*/
public function export($object, \ReflectionObject $reflectionObject) : array
public function export($object, \ReflectionObject $reflectionObject, array $path) : array
{
$lines = $this->getCreateObjectCode($reflectionObject);

Expand Down Expand Up @@ -84,7 +84,10 @@ public function export($object, \ReflectionObject $reflectionObject) : array
$lines[] = '';

foreach ($publicProperties as $name => $value) {
$exportedValue = $this->exporter->export($value);
$newPath = $path;
$newPath[] = $name;

$exportedValue = $this->exporter->export($value, $newPath);
$exportedValue = $this->exporter->wrap($exportedValue, '$object->' . $this->escapePropName($name) . ' = ', ';');
$lines = array_merge($lines, $exportedValue);
}
Expand All @@ -102,7 +105,10 @@ public function export($object, \ReflectionObject $reflectionObject) : array
}

foreach ($nonPublicProperties as $name => $value) {
$exportedValue = $this->exporter->export($value);
$newPath = $path;
$newPath[] = $name;

$exportedValue = $this->exporter->export($value, $newPath);
$exportedValue = $this->exporter->wrap($exportedValue, '$this->' . $this->escapePropName($name) . ' = ', ';');
$closureLines = array_merge($closureLines, $exportedValue);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Internal/ObjectExporter/InternalClassExporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ public function supports(\ReflectionObject $reflectionObject) : bool
/**
* {@inheritDoc}
*/
public function export($object, \ReflectionObject $reflectionObject) : array
public function export($object, \ReflectionObject $reflectionObject, array $path) : array
{
$className = $reflectionObject->getName();

throw new ExportException('Class "' . $className . '" is internal, and cannot be exported.');
throw new ExportException('Class "' . $className . '" is internal, and cannot be exported.', $path);
}
}
4 changes: 2 additions & 2 deletions src/Internal/ObjectExporter/SerializeExporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ public function supports(\ReflectionObject $reflectionObject) : bool
/**
* {@inheritDoc}
*/
public function export($object, \ReflectionObject $reflectionObject) : array
public function export($object, \ReflectionObject $reflectionObject, array $path) : array
{
$lines = $this->getCreateObjectCode($reflectionObject);

$lines[] = '';

$values = $object->__serialize();

$exportedValues = $this->exporter->export($values);
$exportedValues = $this->exporter->export($values, $path);
$exportedValues = $this->exporter->wrap($exportedValues, '$object->__unserialize(', ');');

$lines = array_merge($lines, $exportedValues);
Expand Down
12 changes: 7 additions & 5 deletions src/Internal/ObjectExporter/SetStateExporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ public function supports(\ReflectionObject $reflectionObject) : bool
/**
* {@inheritDoc}
*/
public function export($object, \ReflectionObject $reflectionObject) : array
public function export($object, \ReflectionObject $reflectionObject, array $path) : array
{
$className = $reflectionObject->getName();

$vars = $this->getObjectVars($object);
$vars = $this->getObjectVars($object, $path);

$exportedVars = $this->exporter->exportArray($vars);
$exportedVars = $this->exporter->exportArray($vars, $path);
$exportedVars = $this->exporter->wrap($exportedVars, '\\' . $className . '::__set_state(', ')');

return $exportedVars;
Expand All @@ -56,12 +56,13 @@ public function export($object, \ReflectionObject $reflectionObject) : array
* This way we offer a better safety guarantee, while staying compatible with var_export() in the output.
*
* @param object $object The object to dump.
* @param array $path The path to the object, in the array/object graph.
*
* @return array An associative array of property name to value.
*
* @throws ExportException
*/
private function getObjectVars($object) : array
private function getObjectVars($object, array $path) : array
{
$result = [];

Expand All @@ -77,7 +78,8 @@ private function getObjectVars($object) : array

throw new ExportException(
'Class "' . $className . '" has overridden private property "' . $name . '". ' .
'This is not supported for exporting objects with __set_state().'
'This is not supported for exporting objects with __set_state().',
$path
);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Internal/ObjectExporter/StdClassExporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ public function supports(\ReflectionObject $reflectionObject) : bool
/**
* {@inheritDoc}
*/
public function export($object, \ReflectionObject $reflectionObject) : array
public function export($object, \ReflectionObject $reflectionObject, array $path) : array
{
$exported = $this->exporter->exportArray((array) $object);
$exported = $this->exporter->exportArray((array) $object, $path);

$exported[0] = '(object) ' . $exported[0];

Expand Down
2 changes: 1 addition & 1 deletion tests/VarExporterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public function testExportResource()
$exporter = new VarExporter();

$this->expectException(ExportException::class);
$this->expectExceptionMessage('Type "resource" is not supported.');
$this->expectExceptionMessage('[foo][bar] Type "resource" is not supported.');

$exporter->export($object);
}
Expand Down

0 comments on commit c71662b

Please sign in to comment.