Skip to content

Commit

Permalink
Fix/array access (#4) fixes
Browse files Browse the repository at this point in the history
Fix/array access fixes #3
  • Loading branch information
ReeceM authored May 8, 2019
2 parents 17eb8b6 + 558df53 commit 34bdd68
Show file tree
Hide file tree
Showing 13 changed files with 401 additions and 78 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
composer.lock
vendor
.phpunit.result.cache
coverage/
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ cache:

before_install:
- travis_retry composer self-update
- travis_retry composer dumpautoload

install:
- if [[ $SETUP = 'stable' ]]; then travis_retry composer update --prefer-dist --no-interaction --prefer-stable --no-suggest; fi
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## v1.1.1 - 08.05.19
- add support for array calls
- make the mocked class extend `ArrayObject`
### features
- possibility to make mixed calls to a variable `$data->obj['arrayvalue']->anotherObject`

## v1.1.0 - 04.05.19
- This release adds a more readable output to the __toString() magic method, this is from #1 feature request.

## v1.0.2 - 30.04.19
- change the requirements for the illuminate packages to support laravel/* ^5.6

Expand Down
4 changes: 3 additions & 1 deletion _docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ use ReeceM\Mocker\Mocked;
use ReeceM\Mocker\Utils\VarStore;

$mocked = new Mocked('user', VarStore::singleton());

$mocked->name->class = 'Chips';
$mocked['value']['plus']['another'] = 2;

echo $mocked['value']['plus']['another'] . PHP_EOL;
echo $mocked->name->class . PHP_EOL;

echo $mocked->name->class->data . PHP_EOL;

die(1);
Expand Down
152 changes: 152 additions & 0 deletions _docs/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<?php
/**
* https://stackoverflow.com/questions/11121613/casting-object-to-array-any-magic-method-being-called
* https://www.php.net/manual/en/class.arrayaccess.php
* https://php.net/manual/en/class.arrayobject.php
* LOL - not the only one to do this, mine has memory though :) https://www.php.net/manual/en/language.oop5.iterations.php#81508
*/
// class Test extends ArrayObject {
// private $container = array();
// private $lastOffset;

// public function __construct($history = 0, $input = array() , int $flags = 0, string $iterator_class = "ArrayIterator")
// {
// $this->lastOffset = $history;
// parent::__construct($input, $flags, $iterator_class);
// }

// public function offsetSet($offset, $value) {
// if (is_null($offset)) {
// $this->container[] = $value;
// } else {
// $this->lastOffset = $offset;
// $this->container[$offset] = $value;
// return $this->offsetGet($offset);
// }
// }

// public function offsetGet($offset) {
// $this->lastOffset = $offset;
// return isset($this->container[$offset]) ? $this->container[$offset] : $this->offsetSet($offset, new Test($this->lastOffset));
// }

// public function __toString()
// {
// return 'from array '. (string)$this->lastOffset;
// }

// public function __toArray()
// {
// return json_encode($this);
// }

// public function __get($value)
// {
// return 'from object ' . $value;
// }
// }

class MockedArray extends ArrayObject{
private $container = array();
private $lastOffset;

public function __construct($history = 0, $oldContainer = [])
{
$this->lastOffset = $history;
$this->container = $oldContainer;
parent::__construct();
}

public function getIterator() {
return new ArrayIterator($this->container);
}


public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->lastOffset = $offset;
$this->container[$offset] = $value;
return $this->offsetGet($offset);
}
}

public function offsetGet($offset) {
$this->lastOffset = $offset;
return isset($this->container[$offset]) ? $this->container[$offset] : $this->offsetSet($offset, new MockedArray($offset, $this->container));
}

public function offsetExists($offset)
{
return isset($this->container[$offset]);
}

public function offsetUnset($offset)
{
unset($this->container[$offset]);
}

public function __toString()
{
printf('container: %s </br> offset: %s </br> </br>', json_encode($this->container), $this->lastOffset) .PHP_EOL;
if(isset($this->container[$this->lastOffset])) {
return (json_encode($this->container[$this->lastOffset]));
}
return 'from array '. (string)$this->lastOffset;
}

// public function __toArray()
// {
// return json_encode($this);
// }

public function __get($value)
{
return 'from object ' . $value;
}

// public function __call($name, $arguments)
// {
// $methods = (new \ReflectionClass(array_reverse(debug_backtrace(false))[0]['class']))->getMethods();
// var_export($methods);
// echo PHP_EOL;
// die(1);
// }

public static function __callStatic($name, $arguments)
{

}

private function arrayTrace()
{
// one up...
$selfTrace = debug_backtrace(false, 2);
return [
'function' => $selfTrace[1]['function'] == 'offsetGet' ? '__get' : '__set',
'args' => $selfTrace[1]['args'],
'type' => $selfTrace[1]['type']
];
// return new Mocked(debug_backtrace(false, 1), $this->store, $this->trace);
}
}


$obj = new MockedArray();

$obj['hello']['chips'] = 2;
echo isset($obj['hello']['chips']) . '</br>';

foreach ($obj['list'] as $key => $value) {
echo 'echo </br>' ;
echo $value . PHP_EOL;
}

$obj['test'] = ['key' => 'value'];
$obj['tesffo'] = 'hello';
echo json_encode($obj) . PHP_EOL;
echo $obj['tesffo'] . PHP_EOL;
var_export($obj->__toArray());

echo $obj['address']['street']->OBJECT . PHP_EOL;
4 changes: 4 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,9 @@
"psr-4": {
"Tests\\": "tests/"
}
},
"scripts": {
"test": "vendor/bin/phpunit",
"test-coverage": "vendor/bin/phpunit --coverage-html coverage"
}
}
58 changes: 23 additions & 35 deletions src/Mocked.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@

use Illuminate\Support\Arr;
use ReeceM\Mocker\Utils\VarStore;
use ReeceM\Mocker\Traits\ArrayMagic;
use ReeceM\Mocker\Traits\ObjectMagic;

/**
* the default mocked class that has dynamic variable names and setting of them too
* this is what makes tha fake objects that result from reading un-typed params
*/
class Mocked {
class Mocked extends \ArrayObject{

/**
*
* Array related methods
*/
use ArrayMagic, ObjectMagic;
/**
* the base array from the new call
*/
Expand Down Expand Up @@ -77,11 +84,13 @@ private function structureMockeryCalls()
// merge the preceding calls with this one
array_push($this->previous, $args[0]);
$this->trace = $this->previous;
} else {

} else if($function == self::$SET_METHOD) {
array_push($this->previous, $args[0]);
$this->trace = $this->previous;
$toSet = $args[1];
}

return $this->setMockeryVariables($args[0], $toSet);

} catch (\Exception $th) {
Expand All @@ -94,54 +103,33 @@ private function setMockeryVariables($key, $value = null)
$memorable = $this->store->memoized;

$memorable[$key] = $value;

$this->vars = array_merge($memorable, $this->store->memoized);

$this->store->memoized = $this->vars;
}

public function __get($name)
{
/**
* @todo maybe return the value of the variable if it has been set and has a value
*/
return new Mocked(debug_backtrace(false, 1), $this->store, $this->trace);
}

/**
* Set a method to the calls
*/
public function __call($name, $arguments)
{
// return new Mocked()
}

/**
* set the value of something inside the class
*/
public function __set($name, $value)
{
return new Mocked(debug_backtrace(false, 1), $this->store, $this->trace);
if($value instanceof self) {
$this->store->memoized = array_merge($this->store->memoized, $memorable);
}

$this->store->memoized = array_merge($memorable, $this->store->memoized);
}

/**
* @todo implement __callStatic
*/

/**
* Return a string of the called object
* would be at the end of the whole thing
* @param void
* @return string
*/
public function __toString()
{
{
$calledValue = $this->store->memoized[array_reverse($this->trace)[0]] ?? null;

if($calledValue != null) {
return implode("->", $this->trace) . ' => ' . collect($calledValue);
}

return implode("->", $this->trace);
}

public function __getStore()
{
return $this->store->memoized;
}
}
3 changes: 0 additions & 3 deletions src/ReflectionMockery.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,6 @@ public function reflectionExtractWantedArgs()

public function __get($value) : Mocked
{
if ($value == '__args') {
return $this->__args;
}
return Arr::get($this->__args, $value, $this->reflectionNewClass());
}

Expand Down
72 changes: 72 additions & 0 deletions src/Traits/ArrayMagic.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace ReeceM\Mocker\Traits;

trait ArrayMagic {

/**
* Returns the iterator for loops
* @return \ArrayIterator
*/
public function getIterator() : \ArrayIterator
{
return new \ArrayIterator($this->store->memoized);
}

/**
* sets a value in the array object using the offset
* @param mixed $offset key of the array
* @param mixed $value the value to insert at offset
* @return void|self
*/
public function offsetSet($offset, $value) {

if (is_null($offset)) {
$this->setMockeryVariables($offset, $value);
} else {
$this->setMockeryVariables($offset, $value);
return $this->offsetGet($offset);
}
}

/**
* This gets the value at the offset, if it is not set it will set and return a new instance
*
* @param mixed $offset the offset to get
* @return self
*/
public function offsetGet($offset) {

return isset($this->store->memoized[$offset]) ?
$this->store->memoized[$offset] :
$this->offsetSet($offset, new self($this->arrayTrace(), $this->store, $this->trace));
}

/**
* checks if the key exists in the array
* @return bool
*/
public function offsetExists($offset)
{
return isset($this->store->memoized[$offset]);
}
/**
* unsets a key in array/object
* @return void
*/
public function offsetUnset($offset)
{
unset($this->store->memoized[$offset]);
}

private function arrayTrace() : array
{
// one up...
$selfTrace = debug_backtrace(false, 2);
return array([
'function' => $selfTrace[1]['function'] == 'offsetGet' ? '__get' : '__set',
'args' => $selfTrace[1]['args'] ?? [null],
'type' => $selfTrace[1]['type'] ?? '->'
]);
}
}
Loading

0 comments on commit 34bdd68

Please sign in to comment.