diff --git a/src/Exception/NoAccessException.php b/src/Exception/NoAccessException.php new file mode 100644 index 0000000..6c4ae15 --- /dev/null +++ b/src/Exception/NoAccessException.php @@ -0,0 +1,14 @@ + + * + * Full license available in separate LICENSE file + */ + +namespace Kadet\Functional\Exception; + +class NoAccessException extends FunctionalException +{ +} \ No newline at end of file diff --git a/src/Transforms/index.php b/src/Transforms/index.php index baa482d..17a8bfd 100644 --- a/src/Transforms/index.php +++ b/src/Transforms/index.php @@ -7,4 +7,4 @@ * Full license available in separate LICENSE file */ - +require_once 'objects.php'; diff --git a/src/functions.php b/src/functions.php index 8cc83fc..98cd039 100644 --- a/src/functions.php +++ b/src/functions.php @@ -2,6 +2,7 @@ namespace Kadet\Functional; +use Kadet\Functional\Exception\NoAccessException; use Kadet\Functional\Predicate\AllOfPredicate; use Kadet\Functional\Predicate\AnyOfPredicate; use Kadet\Functional\Predicate\ClosurePredicate; @@ -32,8 +33,24 @@ function predicate($predicate): Predicate } } -function ref(callable $callable) +function ref($callable) { + if (is_array($callable)) { + list($object, $method) = $callable; + $reflection = new \ReflectionObject($object); + $method = $reflection->getMethod($method); + + if (!$method->isPublic()) { + $class = debug_backtrace()[1]['class'] ?? null; + + if ($reflection->name !== $class) { + throw new NoAccessException(sprintf('Method "%s" can only be accessed from inside of object.', $method->name)); + } + } + + return $method->getClosure($object); + } + return \Closure::fromCallable($callable); } @@ -100,7 +117,7 @@ function reflect(callable $callable): \ReflectionFunction case $callable instanceof Decorator: return new ReflectionDecoratedFunction($callable->getDecorated()); default: - return new \ReflectionFunction($callable); + return new \ReflectionFunction(ref($callable)); } } diff --git a/tests/RandomTest.php b/tests/RandomTest.php new file mode 100644 index 0000000..21a0a61 --- /dev/null +++ b/tests/RandomTest.php @@ -0,0 +1,57 @@ + + * + * Full license available in separate LICENSE file + */ + +class TestObject +{ + public function identity($x) + { + return $x; + } + + private function priv() + { + return 'foo'; + } + + public function test() + { + return ref([$this, 'priv']); + } +} + +class RandomTest extends \PHPUnit\Framework\TestCase +{ + public function testApplicationOfArrayNotation() + { + $object = new TestObject(); + $this->assertSame(10, apply([$object, 'identity'], 10)); + } + + public function testReferencingPrivateFunctionsFromInsideOfObject() + { + $object = new TestObject(); + $reference = $object->test(); + + $this->assertSame('foo', $reference()); + } + + /** + * @expectedException \Kadet\Functional\Exception\NoAccessException + */ + public function testReferencingPrivateFunctionsFromOutsideOfObject() + { + $object = new TestObject(); + + ref([$object, 'priv']); + } +} \ No newline at end of file