{"action":"created","comment":{"url":"https://api.github.com/repos/Roave/BetterReflection/pulls/comments/89752464","pull_request_review_id":10287873,"id":89752464,"diff_hunk":"@@ -0,0 +1,287 @@\n+<?php\n+\n+declare(strict_types=1);\n+\n+namespace BetterReflection\\Util\\Visitor;\n+\n+use PhpParser\\NodeVisitorAbstract;\n+use BetterReflection\\Reflection\\ReflectionVariable;\n+use BetterReflection\\TypesFinder\\FindTypeFromAst;\n+use BetterReflection\\Reflection\\ReflectionType;\n+use BetterReflection\\Reflection\\ReflectionClass;\n+use PhpParser\\Node;\n+use PhpParser\\Node\\Expr;\n+use BetterReflection\\Reflector\\Reflector;\n+use phpDocumentor\\Reflection\\Fqsen;\n+use phpDocumentor\\Reflection\\Types as DocType;\n+use phpDocumentor\\Reflection\\TypeResolver;\n+use PhpParser\\Node\\Name;\n+use phpDocumentor\\Reflection\\Type;\n+\n+class VariableCollectionVisitor extends NodeVisitorAbstract\n+{\n+    /**\n+     * @var TypeResolver\n+     */\n+    private $typeResolver;\n+\n+    /**\n+     * @var ReflectionClass\n+     */\n+    private $reflection;\n+\n+    /**\n+     * @var Reflector\n+     */\n+    private $reflector;\n+\n+    /**\n+     * @var array\n+     */\n+    private $variables = [];\n+\n+    /**\n+     * @var array\n+     */\n+    private $methodParamTypes = [];\n+\n+    /**\n+     * Construct with the reflection class for the AST that we are traversing\n+     * and a reflector instance to resolve types from other classes.\n+     */\n+    public function __construct(ReflectionClass $reflection, Reflector $reflector, TypeResolver $typeResolver = null)\n+    {\n+        $this->reflector = $reflector;\n+        $this->reflection = $reflection;\n+        $this->typeResolver = $typeResolver ?: new TypeResolver();\n+    }\n+\n+    /**\n+     * {@inheritdoc}\n+     *\n+     * Just in case this visitor is invoked again, reset the\n+     * variables before traversal starts.\n+     */\n+    public function beforeTraverse(array $nodes)\n+    {\n+        $this->variables = [];\n+    }\n+\n+    /**\n+     * {@inheritdoc}\n+     *\n+     * Currently we care about two types of variables:\n+     *\n+     * 1. Parameters that are passed to class methods.\n+     * 2. Newly declared variables.\n+     */\n+    public function enterNode(Node $node)\n+    {\n+        if ($node instanceof Node\\Stmt\\ClassMethod) {\n+            $this->processClassMethod($node);\n+\n+            return;\n+        }\n+\n+        if ($node instanceof Expr\\Assign) {\n+            $this->processAssign($node);\n+\n+            return;\n+        }\n+    }\n+\n+    /**\n+     * Return all the variables which were discovered in the AST.\n+     *\n+     * @return ReflectionVariable[]\n+     */\n+    public function getVariables()\n+    {\n+        return $this->variables;\n+    }\n+\n+    private function processClassMethod(Node\\Stmt\\ClassMethod $node)\n+    {\n+        // reset when we enter the class method scope\n+        $this->methodParamTypes = [];\n+\n+        $reflMethod = $this->reflection->getMethod($node->name);\n+\n+        foreach ($node->params as $param) {\n+            $reflParam = $reflMethod->getParameter($param->name);\n+\n+            // first use any type hint provided in the method signature.\n+            $type = $reflParam->getType(); /* @var ReflectionType */\n+\n+            // if the type is null, then try and guess the type from the docblock.\n+            if ($reflMethod->getDocComment() && null === $type) {\n+                $types = $reflParam->getDocBlockTypes();\n+\n+                // if multiple types are provided, then return the first.\n+                $type = $this->createReflectionTypeFromDocType(reset($types));\n+            }\n+\n+            // if the type is still null, then assume it as a \"mixed\" type.\n+            $type = $type ?: $this->createReflectionTypeFromString('mixed');\n+\n+            // make the parameter type available for later.\n+            $this->methodParamTypes[$param->name] = $type;\n+\n+            // parameters count as available variables.\n+            $this->variables[] = ReflectionVariable::createFromName($param->name, $type, $param->getAttribute('startLine'));\n+        }\n+    }\n+\n+    private function processAssign(Expr\\Assign $node)\n+    {\n+        // assignment is not directly to a variable, so just ignore it\n+        // rather than trying to recreate state.\n+        if (false === $node->var instanceof Expr\\Variable) {\n+            return;\n+        }\n+\n+        $type = $this->typeFromExpression($node->expr);\n+\n+        $this->variables[] = ReflectionVariable::createFromName($node->var->name, $type, $node->getAttribute('startLine'));\n+    }\n+\n+    private function typeFromExpression(Node $expr): ReflectionType\n+    {\n+        if ($expr instanceof Expr\\New_) {\n+            return $this->createTypeFromNameNode($expr->class);\n+        }\n+\n+        if ($expr instanceof Expr\\PropertyFetch) {\n+            $type = $this->typeFromExpression($expr->var);\n+\n+            if ($type->getTypeObject() instanceof DocType\\Object_) {\n+                $reflection = $this->reflector->reflect($type);\n+                $propertyRefl = $reflection->getProperty($expr->name);\n+\n+                if ($propertyRefl->getDocComment()) {\n+                    $types = $propertyRefl->getDocBlockTypes();\n+\n+                    return $this->createReflectionTypeFromDocType(reset($types));\n+                }\n+            }\n+\n+            return $this->createReflectionTypeFromString('mixed');\n+        }\n+\n+        if ($expr instanceof Expr\\MethodCall) {\n+            $type = $this->typeFromExpression($expr->var);\n+\n+            if ($type->getTypeObject() instanceof DocType\\Object_) {\n+                $reflection = $this->reflector->reflect($type);\n+                $method = $reflection->getMethod($expr->name);\n+\n+                return $method->getReturnType() ?: $this->createReflectionTypeFromString('mixed');\n+            }\n+\n+            return $this->createReflectionTypeFromString('mixed');\n+        }\n+\n+        if ($expr instanceof Expr\\Variable) {\n+            if ($expr->name === 'this') {\n+                $type = $this->createReflectionTypeFromString($this->reflection->getName());\n+\n+                return $type;\n+            }\n+\n+            if (isset($this->methodParamTypes[$expr->name])) {\n+                return $this->methodParamTypes[$expr->name];\n+            }\n+        }\n+\n+        // if this is a function call, try and instantiate the runtime native\n+        // \\ReflectionFunction, if it is not internal then ignore it as we\n+        // cannot guarantee that we are running in the same process as the code\n+        // we are analyzing.\n+        //\n+        // TODO: This is no positive test case for this ... which PHP internal functions\n+        //       actually have a return type??\n+        if ($expr instanceof Expr\\FuncCall) {\n+            $func = (string) $expr->name;\n+            $reflection = new \\ReflectionFunction($func);\n+\n+            // do not try and find out return type for non-internal functions\n+            if (false === $reflection->isInternal()) {\n+                return;\n+            }\n+\n+            // in the case that no return type was provided, just return\n+            // \"mixed\".\n+            return $reflection->getReturnType() ?: $this->createUnknownReflectionType();\n+        }\n+\n+        if ($expr instanceof Expr\\ArrayDimFetch) {\n+            return $this->createUnknownReflectionType();\n+        }\n+\n+        if ($expr instanceof Expr\\Array_) {\n+            return $this->createReflectionTypeFromString('array');\n+        }\n+\n+        if ($expr instanceof Node\\Scalar) {\n+            switch (get_class($expr)) {\n+                case Node\\Scalar\\DNumber::class:\n+                    return $this->createReflectionTypeFromString('float');\n+\n+                case Node\\Scalar\\LNumber::class:\n+                    return $this->createReflectionTypeFromString('integer');\n+\n+                case Node\\Scalar\\String_::class:\n+                    return $this->createReflectionTypeFromString('string');\n+\n+                case Node\\Scalar\\Encapsed::class:\n+                case Node\\Scalar\\MagicConst::class:\n+                case Node\\Scalar\\EncapsedStringPart::class:\n+                    // TODO: ???\n+                    return $this->createUnknownReflectionType();\n+                default:\n+                    throw new \\RuntimeException(sprintf(\n+                        'Do not know scalar type \"%s\"', get_class($expr)\n+                    ));\n+            }\n+        }\n+\n+        throw new \\RuntimeException(sprintf(\n+            'Could not determine type from expression for node of type \"%s\"',\n+            get_class($expr)\n+        ));\n+    }\n+\n+    /**\n+     * Create the a type relative to the current reflection class from\n+     * a php-parser name-node.\n+     */\n+    private function createTypeFromNameNode(Name $name)\n+    {\n+        $docType = (new FindTypeFromAst())->__invoke(\n+            $name,\n+            $this->reflection->getLocatedSource(),\n+            $this->reflection->getNamespaceName()\n+        );\n+\n+        return $this->createReflectionTypeFromDocType($docType);\n+    }\n+\n+    private function createReflectionTypeFromString(string $type = null)\n+    {\n+        $type = $type ?: 'mixed';\n+\n+        return $this->createReflectionTypeFromDocType(\n+            $this->typeResolver->resolve($type)\n+        );\n+    }\n+\n+    private function createReflectionTypeFromDocType(Type $type): ReflectionType\n+    {\n+        return ReflectionType::createFromType($type, false);\n+    }\n+\n+    private function createUnknownReflectionType()\n+    {\n+        return $this->createReflectionTypeFromString('mixed', false);","path":"src/Util/Visitor/VariableCollectionVisitor.php","position":285,"original_position":285,"commit_id":"448b9bae1c458ee24adc9d8cf2886398f2512f9e","original_commit_id":"448b9bae1c458ee24adc9d8cf2886398f2512f9e","user":{"login":"dantleech","id":530801,"avatar_url":"https://avatars.githubusercontent.com/u/530801?v=3","gravatar_id":"","url":"https://api.github.com/users/dantleech","html_url":"https://github.com/dantleech","followers_url":"https://api.github.com/users/dantleech/followers","following_url":"https://api.github.com/users/dantleech/following{/other_user}","gists_url":"https://api.github.com/users/dantleech/gists{/gist_id}","starred_url":"https://api.github.com/users/dantleech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dantleech/subscriptions","organizations_url":"https://api.github.com/users/dantleech/orgs","repos_url":"https://api.github.com/users/dantleech/repos","events_url":"https://api.github.com/users/dantleech/events{/privacy}","received_events_url":"https://api.github.com/users/dantleech/received_events","type":"User","site_admin":false},"body":"What should we do when the type cannot be determined? Currently returning `mixed` - should we return the type as `null`?","created_at":"2016-11-28T10:23:09Z","updated_at":"2016-11-28T10:23:09Z","html_url":"https://github.com/Roave/BetterReflection/pull/224#discussion_r89752464","pull_request_url":"https://api.github.com/repos/Roave/BetterReflection/pulls/224","_links":{"self":{"href":"https://api.github.com/repos/Roave/BetterReflection/pulls/comments/89752464"},"html":{"href":"https://github.com/Roave/BetterReflection/pull/224#discussion_r89752464"},"pull_request":{"href":"https://api.github.com/repos/Roave/BetterReflection/pulls/224"}}},"pull_request":{"url":"https://api.github.com/repos/Roave/BetterReflection/pulls/224","id":95403692,"html_url":"https://github.com/Roave/BetterReflection/pull/224","diff_url":"https://github.com/Roave/BetterReflection/pull/224.diff","patch_url":"https://github.com/Roave/BetterReflection/pull/224.patch","issue_url":"https://api.github.com/repos/Roave/BetterReflection/issues/224","number":224,"state":"open","locked":false,"title":"[WIP] Variable collector","user":{"login":"dantleech","id":530801,"avatar_url":"https://avatars.githubusercontent.com/u/530801?v=3","gravatar_id":"","url":"https://api.github.com/users/dantleech","html_url":"https://github.com/dantleech","followers_url":"https://api.github.com/users/dantleech/followers","following_url":"https://api.github.com/users/dantleech/following{/other_user}","gists_url":"https://api.github.com/users/dantleech/gists{/gist_id}","starred_url":"https://api.github.com/users/dantleech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dantleech/subscriptions","organizations_url":"https://api.github.com/users/dantleech/orgs","repos_url":"https://api.github.com/users/dantleech/repos","events_url":"https://api.github.com/users/dantleech/events{/privacy}","received_events_url":"https://api.github.com/users/dantleech/received_events","type":"User","site_admin":false},"body":"This is an initial attempt at a variable collector (#222), which can be used by the `ReflectionMethod` to determine the variables that are used. The bulk of this code is concerned with resolving types so that:\r\n\r\n```php\r\n/**\r\n * @var Foobar\r\n */\r\npublic function something()\r\n{\r\n     $bar = $this->foobar->getSomeClass()->getFoo();\r\n}\r\n```\r\n\r\nIf the `getSomeClass` method has the return type `SomeClass` class and `SomeClass` a method `getFoo` that returns type `int`, then `$bar` will be resolved to `int`.\r\n\r\n\r\n```php\r\n$reflection = $reflector->reflect(SomeClass::class);\r\n$vars = $reflection->getMethod('something')->getVariables();\r\n\r\necho $vars[0]->getName(); // bar\r\necho $vars[0]->getType(); // int\r\necho $vars[0]->getDeclaredAt(); // 6\r\n```\r\n\r\nThe variable collector visitor can return locally assigned and parameter variables available in the AST it is traversing (regardless of scope).  In the case of getting the variables in a method it would suffice to traverse only the method AST.\r\n\r\nThis is really rough WIP atm and contains an unknown number of bugs, so before reviewing do you agree with the general approach?\r\n\r\nTODO:\r\n\r\n- [ ] Types from static methods/properties.\r\n- [ ] ... ","created_at":"2016-11-27T13:59:48Z","updated_at":"2016-11-28T10:23:09Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7c8682bed6f160c5a0bc4f05b8f3a4bf8027bf03","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/Roave/BetterReflection/pulls/224/commits","review_comments_url":"https://api.github.com/repos/Roave/BetterReflection/pulls/224/comments","review_comment_url":"https://api.github.com/repos/Roave/BetterReflection/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Roave/BetterReflection/issues/224/comments","statuses_url":"https://api.github.com/repos/Roave/BetterReflection/statuses/448b9bae1c458ee24adc9d8cf2886398f2512f9e","head":{"label":"dantleech:variable_collector","ref":"variable_collector","sha":"448b9bae1c458ee24adc9d8cf2886398f2512f9e","user":{"login":"dantleech","id":530801,"avatar_url":"https://avatars.githubusercontent.com/u/530801?v=3","gravatar_id":"","url":"https://api.github.com/users/dantleech","html_url":"https://github.com/dantleech","followers_url":"https://api.github.com/users/dantleech/followers","following_url":"https://api.github.com/users/dantleech/following{/other_user}","gists_url":"https://api.github.com/users/dantleech/gists{/gist_id}","starred_url":"https://api.github.com/users/dantleech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dantleech/subscriptions","organizations_url":"https://api.github.com/users/dantleech/orgs","repos_url":"https://api.github.com/users/dantleech/repos","events_url":"https://api.github.com/users/dantleech/events{/privacy}","received_events_url":"https://api.github.com/users/dantleech/received_events","type":"User","site_admin":false},"repo":{"id":62752910,"name":"BetterReflection","full_name":"dantleech/BetterReflection","owner":{"login":"dantleech","id":530801,"avatar_url":"https://avatars.githubusercontent.com/u/530801?v=3","gravatar_id":"","url":"https://api.github.com/users/dantleech","html_url":"https://github.com/dantleech","followers_url":"https://api.github.com/users/dantleech/followers","following_url":"https://api.github.com/users/dantleech/following{/other_user}","gists_url":"https://api.github.com/users/dantleech/gists{/gist_id}","starred_url":"https://api.github.com/users/dantleech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dantleech/subscriptions","organizations_url":"https://api.github.com/users/dantleech/orgs","repos_url":"https://api.github.com/users/dantleech/repos","events_url":"https://api.github.com/users/dantleech/events{/privacy}","received_events_url":"https://api.github.com/users/dantleech/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/dantleech/BetterReflection","description":"Better Reflection is a reflection API that aims to improve and provide more features than PHP's built-in reflection API.","fork":true,"url":"https://api.github.com/repos/dantleech/BetterReflection","forks_url":"https://api.github.com/repos/dantleech/BetterReflection/forks","keys_url":"https://api.github.com/repos/dantleech/BetterReflection/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dantleech/BetterReflection/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dantleech/BetterReflection/teams","hooks_url":"https://api.github.com/repos/dantleech/BetterReflection/hooks","issue_events_url":"https://api.github.com/repos/dantleech/BetterReflection/issues/events{/number}","events_url":"https://api.github.com/repos/dantleech/BetterReflection/events","assignees_url":"https://api.github.com/repos/dantleech/BetterReflection/assignees{/user}","branches_url":"https://api.github.com/repos/dantleech/BetterReflection/branches{/branch}","tags_url":"https://api.github.com/repos/dantleech/BetterReflection/tags","blobs_url":"https://api.github.com/repos/dantleech/BetterReflection/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dantleech/BetterReflection/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dantleech/BetterReflection/git/refs{/sha}","trees_url":"https://api.github.com/repos/dantleech/BetterReflection/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dantleech/BetterReflection/statuses/{sha}","languages_url":"https://api.github.com/repos/dantleech/BetterReflection/languages","stargazers_url":"https://api.github.com/repos/dantleech/BetterReflection/stargazers","contributors_url":"https://api.github.com/repos/dantleech/BetterReflection/contributors","subscribers_url":"https://api.github.com/repos/dantleech/BetterReflection/subscribers","subscription_url":"https://api.github.com/repos/dantleech/BetterReflection/subscription","commits_url":"https://api.github.com/repos/dantleech/BetterReflection/commits{/sha}","git_commits_url":"https://api.github.com/repos/dantleech/BetterReflection/git/commits{/sha}","comments_url":"https://api.github.com/repos/dantleech/BetterReflection/comments{/number}","issue_comment_url":"https://api.github.com/repos/dantleech/BetterReflection/issues/comments{/number}","contents_url":"https://api.github.com/repos/dantleech/BetterReflection/contents/{+path}","compare_url":"https://api.github.com/repos/dantleech/BetterReflection/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dantleech/BetterReflection/merges","archive_url":"https://api.github.com/repos/dantleech/BetterReflection/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dantleech/BetterReflection/downloads","issues_url":"https://api.github.com/repos/dantleech/BetterReflection/issues{/number}","pulls_url":"https://api.github.com/repos/dantleech/BetterReflection/pulls{/number}","milestones_url":"https://api.github.com/repos/dantleech/BetterReflection/milestones{/number}","notifications_url":"https://api.github.com/repos/dantleech/BetterReflection/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dantleech/BetterReflection/labels{/name}","releases_url":"https://api.github.com/repos/dantleech/BetterReflection/releases{/id}","deployments_url":"https://api.github.com/repos/dantleech/BetterReflection/deployments","created_at":"2016-07-06T20:59:35Z","updated_at":"2016-07-06T20:59:36Z","pushed_at":"2016-11-28T10:19:10Z","git_url":"git://github.com/dantleech/BetterReflection.git","ssh_url":"git@github.com:dantleech/BetterReflection.git","clone_url":"https://github.com/dantleech/BetterReflection.git","svn_url":"https://github.com/dantleech/BetterReflection","homepage":"","size":1112,"stargazers_count":0,"watchers_count":0,"language":"PHP","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"Roave:master","ref":"master","sha":"eed0889e0784d08ef87013223cb6b79d9b76dbe2","user":{"login":"Roave","id":3029050,"avatar_url":"https://avatars.githubusercontent.com/u/3029050?v=3","gravatar_id":"","url":"https://api.github.com/users/Roave","html_url":"https://github.com/Roave","followers_url":"https://api.github.com/users/Roave/followers","following_url":"https://api.github.com/users/Roave/following{/other_user}","gists_url":"https://api.github.com/users/Roave/gists{/gist_id}","starred_url":"https://api.github.com/users/Roave/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Roave/subscriptions","organizations_url":"https://api.github.com/users/Roave/orgs","repos_url":"https://api.github.com/users/Roave/repos","events_url":"https://api.github.com/users/Roave/events{/privacy}","received_events_url":"https://api.github.com/users/Roave/received_events","type":"Organization","site_admin":false},"repo":{"id":36865277,"name":"BetterReflection","full_name":"Roave/BetterReflection","owner":{"login":"Roave","id":3029050,"avatar_url":"https://avatars.githubusercontent.com/u/3029050?v=3","gravatar_id":"","url":"https://api.github.com/users/Roave","html_url":"https://github.com/Roave","followers_url":"https://api.github.com/users/Roave/followers","following_url":"https://api.github.com/users/Roave/following{/other_user}","gists_url":"https://api.github.com/users/Roave/gists{/gist_id}","starred_url":"https://api.github.com/users/Roave/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Roave/subscriptions","organizations_url":"https://api.github.com/users/Roave/orgs","repos_url":"https://api.github.com/users/Roave/repos","events_url":"https://api.github.com/users/Roave/events{/privacy}","received_events_url":"https://api.github.com/users/Roave/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Roave/BetterReflection","description":":crystal_ball: Better Reflection is a reflection API that aims to improve and provide more features than PHP's built-in reflection API.","fork":false,"url":"https://api.github.com/repos/Roave/BetterReflection","forks_url":"https://api.github.com/repos/Roave/BetterReflection/forks","keys_url":"https://api.github.com/repos/Roave/BetterReflection/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Roave/BetterReflection/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Roave/BetterReflection/teams","hooks_url":"https://api.github.com/repos/Roave/BetterReflection/hooks","issue_events_url":"https://api.github.com/repos/Roave/BetterReflection/issues/events{/number}","events_url":"https://api.github.com/repos/Roave/BetterReflection/events","assignees_url":"https://api.github.com/repos/Roave/BetterReflection/assignees{/user}","branches_url":"https://api.github.com/repos/Roave/BetterReflection/branches{/branch}","tags_url":"https://api.github.com/repos/Roave/BetterReflection/tags","blobs_url":"https://api.github.com/repos/Roave/BetterReflection/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Roave/BetterReflection/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Roave/BetterReflection/git/refs{/sha}","trees_url":"https://api.github.com/repos/Roave/BetterReflection/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Roave/BetterReflection/statuses/{sha}","languages_url":"https://api.github.com/repos/Roave/BetterReflection/languages","stargazers_url":"https://api.github.com/repos/Roave/BetterReflection/stargazers","contributors_url":"https://api.github.com/repos/Roave/BetterReflection/contributors","subscribers_url":"https://api.github.com/repos/Roave/BetterReflection/subscribers","subscription_url":"https://api.github.com/repos/Roave/BetterReflection/subscription","commits_url":"https://api.github.com/repos/Roave/BetterReflection/commits{/sha}","git_commits_url":"https://api.github.com/repos/Roave/BetterReflection/git/commits{/sha}","comments_url":"https://api.github.com/repos/Roave/BetterReflection/comments{/number}","issue_comment_url":"https://api.github.com/repos/Roave/BetterReflection/issues/comments{/number}","contents_url":"https://api.github.com/repos/Roave/BetterReflection/contents/{+path}","compare_url":"https://api.github.com/repos/Roave/BetterReflection/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Roave/BetterReflection/merges","archive_url":"https://api.github.com/repos/Roave/BetterReflection/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Roave/BetterReflection/downloads","issues_url":"https://api.github.com/repos/Roave/BetterReflection/issues{/number}","pulls_url":"https://api.github.com/repos/Roave/BetterReflection/pulls{/number}","milestones_url":"https://api.github.com/repos/Roave/BetterReflection/milestones{/number}","notifications_url":"https://api.github.com/repos/Roave/BetterReflection/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Roave/BetterReflection/labels{/name}","releases_url":"https://api.github.com/repos/Roave/BetterReflection/releases{/id}","deployments_url":"https://api.github.com/repos/Roave/BetterReflection/deployments","created_at":"2015-06-04T11:02:42Z","updated_at":"2016-11-19T03:09:31Z","pushed_at":"2016-11-28T10:19:10Z","git_url":"git://github.com/Roave/BetterReflection.git","ssh_url":"git@github.com:Roave/BetterReflection.git","clone_url":"https://github.com/Roave/BetterReflection.git","svn_url":"https://github.com/Roave/BetterReflection","homepage":"","size":1156,"stargazers_count":304,"watchers_count":304,"language":"PHP","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":21,"mirror_url":null,"open_issues_count":31,"forks":21,"open_issues":31,"watchers":304,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Roave/BetterReflection/pulls/224"},"html":{"href":"https://github.com/Roave/BetterReflection/pull/224"},"issue":{"href":"https://api.github.com/repos/Roave/BetterReflection/issues/224"},"comments":{"href":"https://api.github.com/repos/Roave/BetterReflection/issues/224/comments"},"review_comments":{"href":"https://api.github.com/repos/Roave/BetterReflection/pulls/224/comments"},"review_comment":{"href":"https://api.github.com/repos/Roave/BetterReflection/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Roave/BetterReflection/pulls/224/commits"},"statuses":{"href":"https://api.github.com/repos/Roave/BetterReflection/statuses/448b9bae1c458ee24adc9d8cf2886398f2512f9e"}}}}
{"actor":{"display_login":"dantleech"}}