=========================================
Interface declarations
=========================================

<?php

interface ThrowableInterface {
	public function getMessage();
}

class Exception_foo implements ThrowableInterface {
	public $foo = "foo";

	public function getMessage() {
		return $this->foo;
	}
}

---

(program
	(php_tag)
  (interface_declaration
    name: (name)
    body: (declaration_list
      (method_declaration
        (visibility_modifier)
        name: (name)
        parameters: (formal_parameters))))
  (class_declaration
    name: (name)
    (class_interface_clause (name))
    body: (declaration_list
      (property_declaration
        (visibility_modifier)
        (property_element (variable_name (name)) (property_initializer (encapsed_string (string)))))
      (method_declaration
        (visibility_modifier)
        name: (name)
        parameters: (formal_parameters)
        body: (compound_statement
          (return_statement (member_access_expression
            object: (variable_name (name))
            name: (name))))))))

==========================
Use declarations
==========================

<?php

trait AbstractTrait
{
    use LoggerAwareTrait;
    use LoggerAwareTrait, OtherTrait {}
    use LoggerAwareTrait, OtherTrait;
}

class AbstractCache
{
    use AbstractTrait {
        deleteItems as private;
        AbstractTrait::deleteItem as delete;
        AbstractTrait::hasItem as has;
    }
}

---

(program
	(php_tag)
  (trait_declaration
    (name)
    (declaration_list
      (use_declaration (name))
      (use_declaration (name) (name) (use_list))
      (use_declaration (name) (name))))
  (class_declaration
    (name)
    (declaration_list
      (use_declaration
        (name)
        (use_list
          (use_as_clause (name) (visibility_modifier))
          (use_as_clause (class_constant_access_expression (name) (name)) (name))
          (use_as_clause (class_constant_access_expression (name) (name)) (name)))))))

==========================
Namespace names in namespaces
==========================

<?php

namespace Be \ ta {
    class A {}
    class B {}
}

---

(program
	(php_tag)
  (namespace_definition
    name: (namespace_name (name) (name))
    body: (compound_statement
      (class_declaration
        name: (name)
        body: (declaration_list))
      (class_declaration
        name: (name)
        body: (declaration_list)))))

==============================
Class declarations
==============================

<?php
class foo {
  function __construct($name) {
    $GLOBALS['List']= &$this;
    $this->Name = $name;
    $GLOBALS['List']->echoName();
  }

  function echoName() {
    $GLOBALS['names'][]=$this->Name;
  }
}

---

(program
	(php_tag)
  (class_declaration
  name: (name)
	body: (declaration_list
	  (method_declaration
	    name: (name)
	    parameters: (formal_parameters
				(simple_parameter
					name: (variable_name (name))))
	    body: (compound_statement
				(expression_statement (reference_assignment_expression
	        left: (subscript_expression (variable_name (name)) (string))
	        right: (variable_name (name))))
				(expression_statement (assignment_expression
	        left: (member_access_expression
						object: (variable_name (name))
						name: (name))
	        right: (variable_name (name))))
				(expression_statement (member_call_expression
	        object: (subscript_expression (variable_name (name)) (string))
	        name: (name)
	        arguments: (arguments)))))
	  (method_declaration
	    name: (name)
	    parameters: (formal_parameters)
	    body: (compound_statement
	      (expression_statement (assignment_expression
	        left: (subscript_expression (subscript_expression (variable_name (name)) (string)))
	        right: (member_access_expression
						object: (variable_name (name))
						name: (name)))))))))

========================================
Class declarations with base classes
========================================

<?php
class A extends B {

}

---

(program
	(php_tag)
	(class_declaration
		name: (name)
		(base_clause (name))
		body: (declaration_list)))

==========================
Function parameters
==========================

<?php
function test(int $a, string ...$b)
{
}

---

(program
	(php_tag)
	(function_definition
		name: (name)
		parameters: (formal_parameters
			(simple_parameter
				type: (union_type (primitive_type))
				name: (variable_name (name)))
			(variadic_parameter
				type: (union_type (primitive_type))
				name: (variable_name (name))))
		body: (compound_statement)))

====================================
Functions with default parameters
====================================

<?php
function a($arg = self::bar) {
	echo $arg;
}

---

(program
	(php_tag)
	(function_definition
		(name)
		(formal_parameters
			(simple_parameter
				(variable_name (name))
				(class_constant_access_expression (relative_scope) (name))))
		(compound_statement (echo_statement (variable_name (name))))))

========================================================================
Static variables in functions
========================================================================

<?php
function blah()
{
  static $hey=0, $yo=0;
}

---

(program
	(php_tag)
	(function_definition
		(name)
		(formal_parameters)
		(compound_statement
			(function_static_declaration
				(static_variable_declaration (variable_name (name)) (integer))
				(static_variable_declaration (variable_name (name)) (integer))))))

=========================================
Defining Constants
=========================================

<?php

define("CONSTANT", "Hello world.");
const CONSTANT = 'Hello World';
const ANOTHER_CONST = CONSTANT.'; Goodbye World';
const ANIMALS = array('dog', 'cat', 'bird');
define('ANIMALS', array(
    'dog',
    'cat',
    'bird'
));

---

(program
  (php_tag)
  (expression_statement
    (function_call_expression
      (name)
      (arguments
        (argument (encapsed_string (string)))
        (argument (encapsed_string (string)))
      )
    )
  )
  (const_declaration
    (const_element
      (name)
      (string)
    )
  )
  (const_declaration
    (const_element
      (name)
      (binary_expression
        (name)
        (string)
      )
    )
  )
  (const_declaration
    (const_element
      (name)
      (array_creation_expression
        (array_element_initializer (string))
        (array_element_initializer (string))
        (array_element_initializer (string))
      )
    )
  )
  (expression_statement
    (function_call_expression
      (name)
      (arguments
        (argument (string))
        (argument
          (array_creation_expression
            (array_element_initializer (string))
            (array_element_initializer (string))
            (array_element_initializer (string))
          )
        )
      )
    )
  )
)

=======================================
Attributes
=======================================

<?php

#[Test]
function a(#[Test] $a) {
  $c;
}

class PostsController
{
  #[Test]
  const CONSTANT = 'constant value';

  #[Test]
  private string $a = '';

  #[Route("/api/posts/{id}", ["GET"])]
  public function get(#[Test] $id) { /* ... */ }
}

#[MyAttribute]
#[\MyExample\MyAttribute]
#[MyAttribute(1234)]
#[MyAttribute(MyAttribute::VALUE)]
#[MyAttribute(array("key" => "value"))]
#[MyAttribute(100 + 200)]
class Thing
{
}

new #[ExampleAttribute] class() {};
#[ExampleAttribute] fn($x) => $x;
$baz = #[ExampleAttribute] function($x) {return $x;};

---

(program
  (php_tag)

  (function_definition
    attributes: (attribute_list (attribute (name)))
    name: (name)
    parameters: (formal_parameters
      (simple_parameter
        attributes: (attribute_list (attribute (name)))
        name: (variable_name (name))
      )
    )
    body: (compound_statement (expression_statement (variable_name (name))))
  )

  (class_declaration
    name: (name)
    body: (declaration_list
      (const_declaration
        attributes: (attribute_list (attribute (name)))
        (const_element (name) (string))
      )

      (property_declaration
        attributes: (attribute_list (attribute (name)))
        (visibility_modifier)
        type: (union_type (primitive_type))
        (property_element (variable_name (name))
          (property_initializer (string))
        )
      )
      (method_declaration
        attributes: (attribute_list
          (attribute
            (name)
            parameters: (arguments
              (argument (encapsed_string (string)))
              (argument
                (array_creation_expression
                  (array_element_initializer (encapsed_string (string)))
                )
              )
            )
          )
        )
        (visibility_modifier)
        name: (name)
        parameters: (formal_parameters
          (simple_parameter
            attributes: (attribute_list (attribute (name)))
            name: (variable_name (name))
          )
        )
        body: (compound_statement (comment))
      )
    )
  )
  (class_declaration
    attributes: (attribute_list
      (attribute (name))
      (attribute
        (qualified_name
          (namespace_name_as_prefix
            (namespace_name (name))
          )
          (name)
        )
      )
      (attribute
        (name)
        parameters: (arguments (argument (integer)))
      )
      (attribute
        (name)
        parameters: (arguments
          (argument
            (class_constant_access_expression
              (name)
              (name)
            )
          )
        )
      )
      (attribute
        (name)
        parameters: (arguments
          (argument
            (array_creation_expression
              (array_element_initializer
                (encapsed_string (string))
                (encapsed_string (string))
              )
            )
          )
        )
      )
      (attribute
        (name)
        parameters: (arguments
          (argument
            (binary_expression
              left: (integer)
              right: (integer)
            )
          )
        )
      )
    )
    name: (name)
    body: (declaration_list)
  )
  (expression_statement
    (object_creation_expression
      attributes: (attribute_list (attribute (name)))
      (arguments)
      (declaration_list)
    )
  )
  (expression_statement
    (arrow_function
      attributes: (attribute_list (attribute (name)))
      parameters: (formal_parameters
        (simple_parameter
          name: (variable_name (name))
        )
      )
      body: (variable_name (name))
    )
  )
  (expression_statement
    (assignment_expression
      left: (variable_name (name))
      right: (anonymous_function_creation_expression
        attributes: (attribute_list (attribute (name)))
        parameters: (formal_parameters
          (simple_parameter
            name: (variable_name (name))
          )
        )
        body: (compound_statement
          (return_statement
            (variable_name (name))
          )
        )
      )
    )
  )
)


=======================================
Enums
=======================================

<?php

enum A {}
enum B implements Bar, Baz {
}
enum C: int implements Bar {}

enum Suit: string
{
  case Hearts = 'H';
  case Diamonds;
  case Clubs = 'C';
  case Spades = 'S';

  // Fulfills the interface contract.
  public function color(): string {
    return match($this) {
      Suit::Hearts, Suit::Diamonds => 'Red',
      Suit::Clubs, Suit::Spades => 'Black',
    };
  }
}

---

(program
  (php_tag)
  (enum_declaration
    (name)
    (enum_declaration_list)
  )
  (enum_declaration
    (name)
    (class_interface_clause
      (name)
      (name)
    )
    (enum_declaration_list)
  )
  (enum_declaration
    (name)
    (union_type (primitive_type))
    (class_interface_clause (name))
    (enum_declaration_list)
  )
  (enum_declaration
    (name)
    (union_type (primitive_type))
    (enum_declaration_list 
      (enum_case (name) (string))
      (enum_case (name))
      (enum_case (name) (string))
      (enum_case (name) (string))
      
      (comment)
      
      (method_declaration
        (visibility_modifier)
        (name)
        (formal_parameters)
        (union_type (primitive_type))
        (compound_statement
          (return_statement
            (match_expression
              (parenthesized_expression
                (variable_name (name))
              )
              (match_block
                (match_conditional_expression
                  (match_condition_list
                    (class_constant_access_expression (name) (name))
                    (class_constant_access_expression (name) (name))
                  )
                  (string)
                )
                (match_conditional_expression
                  (match_condition_list
                    (class_constant_access_expression (name) (name))
                    (class_constant_access_expression (name) (name))
                  )
                  (string)
                )
              )
            )
          )
        )
      )
    )
  )
)