It begins.
This commit is contained in:
commit
e62663cae7
|
|
@ -0,0 +1,4 @@
|
|||
phpunit.xml
|
||||
composer.lock
|
||||
composer.phar
|
||||
vendor/
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
PHPExporter
|
||||
|
||||
Copyright (c) 2002-2013, Sebastian Bergmann <sebastian@phpunit.de>.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
* Neither the name of Sebastian Bergmann nor the names of his
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
PHPExporter
|
||||
===========
|
||||
|
||||
PHPExporter is a utility for getting textual representations of PHP values.
|
||||
|
||||
```php
|
||||
<?php
|
||||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
use PHPExporter\Exporter;
|
||||
|
||||
// 46
|
||||
echo Exporter::export(46);
|
||||
|
||||
// 4.0
|
||||
echo Exporter::export(4.0);
|
||||
|
||||
// 'hello, world!'
|
||||
echo Exporter::export('hello, world!');
|
||||
|
||||
// false
|
||||
echo Exporter::export(false);
|
||||
|
||||
// NAN
|
||||
echo Exporter::export(acos(8));
|
||||
|
||||
// -INF
|
||||
echo Exporter::export(log(0));
|
||||
|
||||
// null
|
||||
echo Exporter::export(null);
|
||||
|
||||
// resource(13) of type (stream)
|
||||
echo Exporter::export(fopen('php://stderr', 'w'));
|
||||
|
||||
/*
|
||||
Array &0 (
|
||||
0 => Array &1 (
|
||||
0 => 1
|
||||
1 => 2
|
||||
2 => 3
|
||||
)
|
||||
1 => Array &2 (
|
||||
0 => ''
|
||||
1 => 0
|
||||
2 => false
|
||||
)
|
||||
)
|
||||
*/
|
||||
echo Exporter::export(array(array(1,2,3), array("",0,FALSE)));
|
||||
|
||||
|
||||
// Array with references
|
||||
// ----------------------
|
||||
$array = array();
|
||||
$array['self'] = &$array;
|
||||
echo Exporter::export($array);
|
||||
/*
|
||||
Array &0 (
|
||||
'self' => Array &1 (
|
||||
'self' => Array &1
|
||||
)
|
||||
)
|
||||
*/
|
||||
|
||||
|
||||
// Object with references
|
||||
// ----------------------
|
||||
$obj = new stdClass();
|
||||
$obj->self = $obj;
|
||||
echo Exporter::export($obj);
|
||||
/*
|
||||
stdClass Object &0000000003a66dcc0000000025e723e2 (
|
||||
'self' => stdClass Object &0000000003a66dcc0000000025e723e2
|
||||
)
|
||||
*/
|
||||
|
||||
|
||||
// Kitchen Sink
|
||||
// ------------
|
||||
$obj2 = new stdClass;
|
||||
$obj2->foo = 'bar';
|
||||
$obj = new stdClass;
|
||||
$obj->null = NULL;
|
||||
$obj->boolean = TRUE;
|
||||
$obj->integer = 1;
|
||||
$obj->double = 1.2;
|
||||
$obj->string = '1';
|
||||
$obj->text = "this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext";
|
||||
$obj->object = $obj2;
|
||||
$obj->objectagain = $obj2;
|
||||
$obj->array = array('foo' => 'bar');
|
||||
$obj->self = $obj;
|
||||
$array = array(
|
||||
0 => 0,
|
||||
'null' => NULL,
|
||||
'boolean' => TRUE,
|
||||
'integer' => 1,
|
||||
'double' => 1.2,
|
||||
'string' => '1',
|
||||
'text' => "this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext",
|
||||
'object' => $obj2,
|
||||
'objectagain' => $obj2,
|
||||
'array' => array('foo' => 'bar'),
|
||||
);
|
||||
$array['self'] = &$array;
|
||||
echo Exporter::export($array);
|
||||
/*
|
||||
Array &0 (
|
||||
0 => 0
|
||||
'null' => null
|
||||
'boolean' => true
|
||||
'integer' => 1
|
||||
'double' => 1.2
|
||||
'string' => '1'
|
||||
'text' => 'this
|
||||
is
|
||||
a
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
long
|
||||
text'
|
||||
'object' => stdClass Object &000000007ed49b01000000006907e890 (
|
||||
'foo' => 'bar'
|
||||
)
|
||||
'objectagain' => stdClass Object &000000007ed49b01000000006907e890
|
||||
'array' => Array &1 (
|
||||
'foo' => 'bar'
|
||||
)
|
||||
'self' => Array &2 (
|
||||
0 => 0
|
||||
'null' => null
|
||||
'boolean' => true
|
||||
'integer' => 1
|
||||
'double' => 1.2
|
||||
'string' => '1'
|
||||
'text' => 'this
|
||||
is
|
||||
a
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
long
|
||||
text'
|
||||
'object' => stdClass Object &000000007ed49b01000000006907e890
|
||||
'objectagain' => stdClass Object &000000007ed49b01000000006907e890
|
||||
'array' => Array &3 (
|
||||
'foo' => 'bar'
|
||||
)
|
||||
'self' => Array &2
|
||||
)
|
||||
)
|
||||
*/
|
||||
|
||||
```
|
||||
|
||||
PHPExporter works with PHP 5.3.3 or later.
|
||||
|
||||
## Installation
|
||||
|
||||
The recommended way to install PHPExporter is [through
|
||||
composer](http://getcomposer.org). Just create a `composer.json` file and
|
||||
run the `php composer.phar install` command to install it:
|
||||
|
||||
{
|
||||
"require": {
|
||||
"phpexporter/phpexporter": "1.0.*@dev"
|
||||
}
|
||||
}
|
||||
|
||||
## Tests
|
||||
|
||||
To run the test suite, you need [composer](http://getcomposer.org).
|
||||
|
||||
$ php composer.phar install --dev
|
||||
$ phpunit
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
This utility was adapted from the
|
||||
[PHPUnit](https://github.com/sebastianbergmann/phpunit/) project. A special
|
||||
thanks goes to the following people for their contributions:
|
||||
|
||||
* [sebastianbergmann](https://github.com/sebastianbergmann)
|
||||
* [edorian](https://github.com/edorian)
|
||||
* [LawnGnome](https://github.com/LawnGnome)
|
||||
* [bschussek](https://github.com/bschussek)
|
||||
|
||||
## License
|
||||
|
||||
PHPExporter is licensed under the BSD 3-Clause license.
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"name": "phpexporter/phpexporter",
|
||||
"description": "Textual representations of PHP values (Adapted from PHPUnit_Util_Type)",
|
||||
"keywords": ["exporter"],
|
||||
"homepage": "http://www.github.com/whatthejeff/PHPExporter",
|
||||
"license": "BSD-3-Clause",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jeff Welch",
|
||||
"email": "whatthejeff@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
},
|
||||
{
|
||||
"name": "Volker Dusch",
|
||||
"email": "github@wallbash.com"
|
||||
},
|
||||
{
|
||||
"name": "Adam Harvey",
|
||||
"email": "aharvey@php.net"
|
||||
},
|
||||
{
|
||||
"name": "Bernhard Schussek",
|
||||
"email": "bschussek@2bepublished.at"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "3.7.*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": { "PHPExporter": "src/" }
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="PHPExporter Test Suite">
|
||||
<directory>./tests/PHPExporter/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory>./src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
<?php
|
||||
/**
|
||||
* PHPExporter
|
||||
*
|
||||
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the name of Sebastian Bergmann nor the names of his
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package PHPExporter
|
||||
* @author Sebastian Bergmann <sebastian@phpunit.de>
|
||||
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
|
||||
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
|
||||
* @link http://www.github.com/whatthejeff/PHPExporter
|
||||
*/
|
||||
|
||||
namespace PHPExporter;
|
||||
|
||||
/**
|
||||
* Textual representations of PHP values (Adapted from PHPUnit_Util_Type).
|
||||
*
|
||||
* @package PHPExporter
|
||||
* @author Sebastian Bergmann <sebastian@phpunit.de>
|
||||
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
|
||||
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
|
||||
* @link http://www.github.com/whatthejeff/PHPExporter
|
||||
*/
|
||||
class Exporter
|
||||
{
|
||||
/**
|
||||
* Exports a value into a string
|
||||
*
|
||||
* The output of this method is similar to the output of print_r(), but
|
||||
* improved in various aspects:
|
||||
*
|
||||
* - NULL is rendered as "null" (instead of "")
|
||||
* - TRUE is rendered as "true" (instead of "1")
|
||||
* - FALSE is rendered as "false" (instead of "")
|
||||
* - Strings are always quoted with single quotes
|
||||
* - Carriage returns and newlines are normalized to \n
|
||||
* - Recursion and repeated rendering is treated properly
|
||||
*
|
||||
* @param mixed $value The value to export
|
||||
* @param integer $indentation The indentation level of the 2nd+ line
|
||||
* @return string
|
||||
*/
|
||||
public static function export($value, $indentation = 0)
|
||||
{
|
||||
return self::recursiveExport($value, $indentation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive implementation of export
|
||||
*
|
||||
* @param mixed $value The value to export
|
||||
* @param integer $indentation The indentation level of the 2nd+ line
|
||||
* @param PHPExporter\ExporterContext $processed Contains all objects
|
||||
* and arrays that have
|
||||
* previously been
|
||||
* rendered
|
||||
* @return string
|
||||
* @see PHPExporter\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 ExporterContext;
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
if (($key = $processed->contains($value)) !== false) {
|
||||
return "Array &$key";
|
||||
}
|
||||
|
||||
$key = $processed->add($value);
|
||||
if (count($value) > 0) {
|
||||
$output = "Array &$key (\n";
|
||||
|
||||
foreach ($value as $k => $v) {
|
||||
$ek = self::export($k);
|
||||
$output .= "$whitespace $ek => ".self::recursiveExport($value[$k], $indentation + 1, $processed)."\n";
|
||||
}
|
||||
|
||||
return "$output$whitespace)";
|
||||
} else {
|
||||
return "Array &$key ()";
|
||||
}
|
||||
}
|
||||
|
||||
if (is_object($value)) {
|
||||
$class = get_class($value);
|
||||
|
||||
if ($hash = $processed->contains($value)) {
|
||||
return "$class Object &$hash";
|
||||
}
|
||||
|
||||
$hash = $processed->add($value);
|
||||
$array = self::toArray($value);
|
||||
if (count($array) > 0) {
|
||||
$output = "$class Object &$hash (\n";
|
||||
|
||||
foreach ($array as $k => $v) {
|
||||
$k = self::export($k);
|
||||
$output .= "$whitespace $k => ".self::recursiveExport($v, $indentation + 1, $processed)."\n";
|
||||
}
|
||||
|
||||
return "$output$whitespace)";
|
||||
} else {
|
||||
return "$class Object &$hash ()";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return var_export($value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports a value into a single-line string
|
||||
*
|
||||
* The output of this method is similar to the output of
|
||||
* PHPExporter\Exporter::export. This method guarantees thought that the
|
||||
* result contains now newlines.
|
||||
*
|
||||
* Newlines are replaced by the visible string '\n'. Contents of arrays
|
||||
* and objects (if any) are replaced by '...'.
|
||||
*
|
||||
* @param mixed $value The value to export
|
||||
* @param integer $indentation The indentation level of the 2nd+ line
|
||||
* @return string
|
||||
* @see PHPExporter\Exporter::export
|
||||
*/
|
||||
public static function shortenedExport($value)
|
||||
{
|
||||
if (is_string($value)) {
|
||||
return self::shortenedString($value);
|
||||
}
|
||||
|
||||
if(is_object($value)) {
|
||||
return sprintf(
|
||||
"%s Object (%s)",
|
||||
get_class($value),
|
||||
count(self::toArray($value)) > 0 ? '...' : ''
|
||||
);
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
return sprintf(
|
||||
"Array (%s)",
|
||||
count($value) > 0 ? '...' : ''
|
||||
);
|
||||
}
|
||||
|
||||
return self::export($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortens a string and converts all new lines to '\n'
|
||||
*
|
||||
* @param string $string The string to shorten
|
||||
* @param integer $max The maximum length for the string
|
||||
* @return string
|
||||
*/
|
||||
public static function shortenedString($string, $maxLength = 40)
|
||||
{
|
||||
$string = self::export($string);
|
||||
|
||||
if (strlen($string) > $maxLength) {
|
||||
$string = substr($string, 0, $maxLength - 10) . '...' . substr($string, -7);
|
||||
}
|
||||
|
||||
return str_replace("\n", '\n', $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an object to an array containing all of its private, protected
|
||||
* and public properties.
|
||||
*
|
||||
* @param object $object
|
||||
* @return array
|
||||
*/
|
||||
public static function toArray($object)
|
||||
{
|
||||
$array = array();
|
||||
|
||||
foreach ((array)$object as $key => $value) {
|
||||
// properties are transformed to keys in the following way:
|
||||
|
||||
// private $property => "\0Classname\0property"
|
||||
// protected $property => "\0*\0property"
|
||||
// public $property => "property"
|
||||
|
||||
if (preg_match('/^\0.+\0(.+)$/', $key, $matches)) {
|
||||
$key = $matches[1];
|
||||
}
|
||||
|
||||
$array[$key] = $value;
|
||||
}
|
||||
|
||||
// Some internal classes like SplObjectStorage don't work with the
|
||||
// above (fast) mechanism nor with reflection
|
||||
// Format the output similarly to print_r() in this case
|
||||
if ($object instanceof \SplObjectStorage) {
|
||||
foreach ($object as $key => $value) {
|
||||
$array[spl_object_hash($value)] = array(
|
||||
'obj' => $value,
|
||||
'inf' => $object->getInfo(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
<?php
|
||||
/**
|
||||
* PHPExporter
|
||||
*
|
||||
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the name of Sebastian Bergmann nor the names of his
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package PHPExporter
|
||||
* @author Adam Harvey <aharvey@php.net>
|
||||
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
|
||||
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
|
||||
* @link http://www.github.com/whatthejeff/PHPExporter
|
||||
*/
|
||||
|
||||
namespace PHPExporter;
|
||||
|
||||
/**
|
||||
* A context containing previously rendered arrays and objects when recursively
|
||||
* exporting a value.
|
||||
*
|
||||
* @package PHPExporter
|
||||
* @author Adam Harvey <aharvey@php.net>
|
||||
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
|
||||
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
|
||||
* @link http://www.github.com/whatthejeff/PHPExporter
|
||||
*/
|
||||
class ExporterContext {
|
||||
/**
|
||||
* Previously seen arrays.
|
||||
*
|
||||
* @var array[] $arrays
|
||||
*/
|
||||
protected $arrays;
|
||||
|
||||
/**
|
||||
* Previously seen objects.
|
||||
*
|
||||
* @var SplObjectStorage $objects
|
||||
*/
|
||||
protected $objects;
|
||||
|
||||
/** Initialises the context. */
|
||||
public function __construct()
|
||||
{
|
||||
$this->arrays = array();
|
||||
$this->objects = new \SplObjectStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a value to the export context.
|
||||
*
|
||||
* @param mixed $value The value to add.
|
||||
* @return mixed The ID of the stored value, either as a string or integer.
|
||||
* @throws PHPExporter\ExporterContext Thrown if $value is not an array or
|
||||
* object.
|
||||
*/
|
||||
public function add(&$value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return $this->addArray($value);
|
||||
} elseif (is_object($value)) {
|
||||
return $this->addObject($value);
|
||||
}
|
||||
|
||||
throw new ExporterException('Only arrays and objects are supported');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given value exists within the context.
|
||||
*
|
||||
* @param mixed $value The value to check.
|
||||
* @return mixed The string or integer ID of the stored value if it has
|
||||
* already been seen, or boolean false if the value is not
|
||||
* stored.
|
||||
* @throws PHPExporter\ExporterContext Thrown if $value is not an array or
|
||||
* object.
|
||||
*/
|
||||
public function contains(&$value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return $this->containsArray($value);
|
||||
} elseif (is_object($value)) {
|
||||
return $this->containsObject($value);
|
||||
}
|
||||
|
||||
throw new ExporterException('Only arrays and objects are supported');
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores an array within the context.
|
||||
*
|
||||
* @param array $value The value to store.
|
||||
* @return integer The internal ID of the array.
|
||||
*/
|
||||
protected function addArray(array &$value)
|
||||
{
|
||||
if (($key = $this->containsArray($value)) !== false) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
$this->arrays[] = &$value;
|
||||
return count($this->arrays) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores an object within the context.
|
||||
*
|
||||
* @param object $value
|
||||
* @return string The ID of the object.
|
||||
*/
|
||||
protected function addObject($value)
|
||||
{
|
||||
if (!$this->objects->contains($value)) {
|
||||
$this->objects->attach($value);
|
||||
}
|
||||
|
||||
return spl_object_hash($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given array exists within the context.
|
||||
*
|
||||
* @param array $value The array to check.
|
||||
* @return mixed The integer ID of the array if it exists, or boolean false
|
||||
* otherwise.
|
||||
*/
|
||||
protected function containsArray(array &$value)
|
||||
{
|
||||
$keys = array_keys($this->arrays, $value, true);
|
||||
$gen = '_PHPExporter_Key_'.hash('sha512', microtime(true));
|
||||
foreach ($keys as $key) {
|
||||
$this->arrays[$key][$gen] = $gen;
|
||||
if (isset($value[$gen]) && $value[$gen] === $gen) {
|
||||
unset($this->arrays[$key][$gen]);
|
||||
return $key;
|
||||
}
|
||||
unset($this->arrays[$key][$gen]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given object exists within the context.
|
||||
*
|
||||
* @param object $value The object to check.
|
||||
* @return mixed The string ID of the object if it exists, or boolean false
|
||||
* otherwise.
|
||||
*/
|
||||
protected function containsObject($value)
|
||||
{
|
||||
if ($this->objects->contains($value)) {
|
||||
return spl_object_hash($value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
/**
|
||||
* PHPExporter
|
||||
*
|
||||
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the name of Sebastian Bergmann nor the names of his
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package PHPUnit
|
||||
* @subpackage Framework
|
||||
* @author Sebastian Bergmann <sebastian@phpunit.de>
|
||||
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
|
||||
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
|
||||
* @link http://www.github.com/whatthejeff/PHPExporter
|
||||
*/
|
||||
|
||||
namespace PHPExporter;
|
||||
|
||||
/**
|
||||
* Exception for PHPExporter runtime errors.
|
||||
*
|
||||
* @package PHPExporter
|
||||
* @author Sebastian Bergmann <sebastian@phpunit.de>
|
||||
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
|
||||
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
|
||||
* @link http://www.github.com/whatthejeff/PHPExporter
|
||||
*/
|
||||
class ExporterException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,306 @@
|
|||
<?php
|
||||
/**
|
||||
* PHPExporter
|
||||
*
|
||||
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the name of Sebastian Bergmann nor the names of his
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package PHPExporter
|
||||
* @author Bernhard Schussek <bschussek@2bepublished.at>
|
||||
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
|
||||
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
|
||||
* @link http://www.github.com/whatthejeff/PHPExporter
|
||||
*/
|
||||
|
||||
use PHPExporter\Exporter;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @package PHPExporter
|
||||
* @author Bernhard Schussek <bschussek@2bepublished.at>
|
||||
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
|
||||
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
|
||||
* @link http://www.github.com/whatthejeff/PHPExporter
|
||||
*/
|
||||
class ExporterTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Removes spaces in front newlines
|
||||
*
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
public static function trimnl($string)
|
||||
{
|
||||
return preg_replace('/[ ]*\n/', "\n", $string);
|
||||
}
|
||||
|
||||
public function exportProvider()
|
||||
{
|
||||
$obj2 = new stdClass;
|
||||
$obj2->foo = 'bar';
|
||||
|
||||
$obj = new stdClass;
|
||||
//@codingStandardsIgnoreStart
|
||||
$obj->null = NULL;
|
||||
//@codingStandardsIgnoreEnd
|
||||
$obj->boolean = TRUE;
|
||||
$obj->integer = 1;
|
||||
$obj->double = 1.2;
|
||||
$obj->string = '1';
|
||||
$obj->text = "this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext";
|
||||
$obj->object = $obj2;
|
||||
$obj->objectagain = $obj2;
|
||||
$obj->array = array('foo' => 'bar');
|
||||
$obj->self = $obj;
|
||||
|
||||
$array = array(
|
||||
0 => 0,
|
||||
'null' => NULL,
|
||||
'boolean' => TRUE,
|
||||
'integer' => 1,
|
||||
'double' => 1.2,
|
||||
'string' => '1',
|
||||
'text' => "this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext",
|
||||
'object' => $obj2,
|
||||
'objectagain' => $obj2,
|
||||
'array' => array('foo' => 'bar'),
|
||||
);
|
||||
|
||||
$array['self'] = &$array;
|
||||
|
||||
return array(
|
||||
array(NULL, 'null'),
|
||||
array(TRUE, 'true'),
|
||||
array(1, '1'),
|
||||
array(1.0, '1.0'),
|
||||
array(1.2, '1.2'),
|
||||
array(fopen('php://memory', 'r'), 'resource(%d) of type (stream)'),
|
||||
array('1', "'1'"),
|
||||
array(array(array(1,2,3), array(3,4,5)),
|
||||
<<<EOF
|
||||
Array &0 (
|
||||
0 => Array &1 (
|
||||
0 => 1
|
||||
1 => 2
|
||||
2 => 3
|
||||
)
|
||||
1 => Array &2 (
|
||||
0 => 3
|
||||
1 => 4
|
||||
2 => 5
|
||||
)
|
||||
)
|
||||
EOF
|
||||
),
|
||||
// \n\r and \r is converted to \n
|
||||
array("this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext",
|
||||
<<<EOF
|
||||
'this
|
||||
is
|
||||
a
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
long
|
||||
text'
|
||||
EOF
|
||||
),
|
||||
array(new stdClass, 'stdClass Object &%x ()'),
|
||||
array($obj,
|
||||
<<<EOF
|
||||
stdClass Object &%x (
|
||||
'null' => null
|
||||
'boolean' => true
|
||||
'integer' => 1
|
||||
'double' => 1.2
|
||||
'string' => '1'
|
||||
'text' => 'this
|
||||
is
|
||||
a
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
long
|
||||
text'
|
||||
'object' => stdClass Object &%x (
|
||||
'foo' => 'bar'
|
||||
)
|
||||
'objectagain' => stdClass Object &%x
|
||||
'array' => Array &%d (
|
||||
'foo' => 'bar'
|
||||
)
|
||||
'self' => stdClass Object &%x
|
||||
)
|
||||
EOF
|
||||
),
|
||||
array(array(), 'Array &%d ()'),
|
||||
array($array,
|
||||
<<<EOF
|
||||
Array &%d (
|
||||
0 => 0
|
||||
'null' => null
|
||||
'boolean' => true
|
||||
'integer' => 1
|
||||
'double' => 1.2
|
||||
'string' => '1'
|
||||
'text' => 'this
|
||||
is
|
||||
a
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
long
|
||||
text'
|
||||
'object' => stdClass Object &%x (
|
||||
'foo' => 'bar'
|
||||
)
|
||||
'objectagain' => stdClass Object &%x
|
||||
'array' => Array &%d (
|
||||
'foo' => 'bar'
|
||||
)
|
||||
'self' => Array &%d (
|
||||
0 => 0
|
||||
'null' => null
|
||||
'boolean' => true
|
||||
'integer' => 1
|
||||
'double' => 1.2
|
||||
'string' => '1'
|
||||
'text' => 'this
|
||||
is
|
||||
a
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
very
|
||||
long
|
||||
text'
|
||||
'object' => stdClass Object &%x
|
||||
'objectagain' => stdClass Object &%x
|
||||
'array' => Array &%d (
|
||||
'foo' => 'bar'
|
||||
)
|
||||
'self' => Array &%d
|
||||
)
|
||||
)
|
||||
EOF
|
||||
),
|
||||
array(
|
||||
chr(0) . chr(1) . chr(2) . chr(3) . chr(4) . chr(5),
|
||||
'Binary String: 0x000102030405'
|
||||
),
|
||||
array(
|
||||
implode('', array_map('chr', range(0x0e, 0x1f))),
|
||||
'Binary String: 0x0e0f101112131415161718191a1b1c1d1e1f'
|
||||
),
|
||||
array(
|
||||
chr(0x00) . chr(0x09),
|
||||
'Binary String: 0x0009'
|
||||
),
|
||||
array(
|
||||
'',
|
||||
"''"
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider exportProvider
|
||||
*/
|
||||
public function testExport($value, $expected)
|
||||
{
|
||||
$this->assertStringMatchesFormat($expected, self::trimnl(Exporter::export($value)));
|
||||
}
|
||||
|
||||
public function shortenedExportProvider()
|
||||
{
|
||||
$obj = new stdClass;
|
||||
$obj->foo = 'bar';
|
||||
|
||||
$array = array(
|
||||
'foo' => 'bar',
|
||||
);
|
||||
|
||||
return array(
|
||||
array(NULL, 'null'),
|
||||
array(TRUE, 'true'),
|
||||
array(1, '1'),
|
||||
array(1.0, '1.0'),
|
||||
array(1.2, '1.2'),
|
||||
array('1', "'1'"),
|
||||
// \n\r and \r is converted to \n
|
||||
array("this\nis\na\nvery\nvery\nvery\nvery\nvery\nvery\rlong\n\rtext", "'this\\nis\\na\\nvery\\nvery\\nvery\\nvery...g\\ntext'"),
|
||||
array(new stdClass, 'stdClass Object ()'),
|
||||
array($obj, 'stdClass Object (...)'),
|
||||
array(array(), 'Array ()'),
|
||||
array($array, 'Array (...)'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider shortenedExportProvider
|
||||
*/
|
||||
public function testShortenedExport($value, $expected)
|
||||
{
|
||||
$this->assertSame($expected, self::trimnl(Exporter::shortenedExport($value)));
|
||||
}
|
||||
|
||||
public function provideNonBinaryMultibyteStrings()
|
||||
{
|
||||
return array(
|
||||
array(implode('', array_map('chr', range(0x09, 0x0d))), 5),
|
||||
array(implode('', array_map('chr', range(0x20, 0x7f))), 96),
|
||||
array(implode('', array_map('chr', range(0x80, 0xff))), 128),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @dataProvider provideNonBinaryMultibyteStrings
|
||||
*/
|
||||
public function testNonBinaryStringExport($value, $expectedLength)
|
||||
{
|
||||
$this->assertRegExp("~'.{{$expectedLength}}'\$~s", Exporter::export($value));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue