<?php

function bar($param1)
{
    return $param1;
}


$closure = function($param1) {
    return $param1;
};

function test($fn)
{
    static $count = 0;
    $input = "foo".$count;
    $count++;

    $output = $fn($input);
    return $input === $output;
}

class Foo
{
    public static function publicStaticFunction($param1)
    {
        return $param1;
    }

    private static function privateStaticFunction($param1)
    {
        return $param1;
    }

    protected static function protectedStaticFunction($param1)
    {
        return $param1;
    }

    private function privateInstanceFunc($param1)
    {
        return $param1;
    }

    protected function protectedInstanceFunc($param1)
    {
        return $param1;
    }


    public function publicInstanceFunc($param1)
    {
        return $param1;
    }

    public function closePrivateValid()
    {
        return Closure::fromCallable([$this, 'privateInstanceFunc']);
    }

    public function closePrivateStatic()
    {
        return Closure::fromCallable([__CLASS__, 'privateStaticFunction']);
    }

    public function bar($param1)
    {
        echo "this is bar\n";
    }

    public function getCallable()
    {
        return Closure::fromCallable([$this, 'publicInstanceFunc']);
    }

    public function getSelfPublicInstance()
    {
        return Closure::fromCallable([$this, 'publicInstanceFunc']);
    }

    public function getSelfColonPublicInstanceMethod()
    {
        return Closure::fromCallable('self::publicInstanceFunc');
    }
}



class SubFoo extends Foo {

    public function closePrivateStaticInvalid()
    {
        return Closure::fromCallable([__CLASS__, 'privateStaticFunction']);
    }


    public function closePrivateInvalid()
    {
        return Closure::fromCallable([$this, 'privateInstanceFunc']);
    }

    public function closeProtectedStaticMethod()
    {
        return Closure::fromCallable([__CLASS__, 'protectedStaticFunction']);
    }

    public function closeProtectedValid()
    {
        return Closure::fromCallable([$this, 'protectedInstanceFunc']);
    }

    public function getParentPublicInstanceMethod()
    {
        return Closure::fromCallable('parent::publicInstanceFunc');
    }

    public function getSelfColonParentPublicInstanceMethod()
    {
        return Closure::fromCallable('self::publicInstanceFunc');
    }


    public function getSelfColonParentProtectedInstanceMethod()
    {
        return Closure::fromCallable('self::protectedInstanceFunc');
    }

    public function getSelfColonParentPrivateInstanceMethod()
    {
        return Closure::fromCallable('self::privateInstanceFunc');
    }
}


class MagicCall
{
    public function __call($name, $arguments)
    {
        $info = ['__call'];
        $info[] = $name;
        $info = array_merge($info, $arguments);
        return implode(',', $info);
    }

    public static function __callStatic($name, $arguments)
    {
        $info = ['__callStatic'];
        $info[] = $name;
        $info = array_merge($info, $arguments);
        return implode(',', $info);
    }
}



class PublicInvocable
{
    public function __invoke($param1)
    {
        return $param1;
    }
}


function functionAccessProtected()
{
    $foo = new Foo;

    return Closure::fromCallable([$foo, 'protectedStaticFunction']);
}

function functionAccessPrivate()
{
    $foo = new Foo;

    return Closure::fromCallable([$foo, 'privateStaticFunction']);
}


function functionAccessMethodDoesntExist()
{
    $foo = new Foo;

    return Closure::fromCallable([$foo, 'thisDoesNotExist']);
}

?>
