Repository: hhvm/hack-langspec
Branch: master
Commit: 007011a2dd06
Files: 528
Total size: 1.5 MB
Directory structure:
gitextract_tmng50ms/
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── FORMATTING.md
├── LICENSE
├── README.md
├── spec/
│ ├── 00-specification-for-hack.md
│ ├── 01-introduction.md
│ ├── 02-conformance.md
│ ├── 03-terms-and-definitions.md
│ ├── 04-basic-concepts.md
│ ├── 05-types.md
│ ├── 06-constants.md
│ ├── 07-variables.md
│ ├── 08-conversions.md
│ ├── 09-lexical-structure.md
│ ├── 10-expressions.md
│ ├── 11-statements.md
│ ├── 12-script-inclusion.md
│ ├── 13-enums.md
│ ├── 14-generic-types-methods-and-functions.md
│ ├── 15-functions.md
│ ├── 16-classes.md
│ ├── 17-interfaces.md
│ ├── 18-traits.md
│ ├── 19-exception-handling.md
│ ├── 20-namespaces.md
│ ├── 21-attributes.md
│ ├── 22-grammar.md
│ ├── 23-differences-from-php.md
│ ├── 24-bibliography.md
│ └── hack-spec-draft.md
├── tests/
│ ├── .hhconfig
│ ├── Attributes/
│ │ ├── .hhconfig
│ │ ├── __ConsistentConstruct.php
│ │ ├── __ConsistentConstruct.php.expect
│ │ ├── __Memoize.php
│ │ ├── __Memoize.php.expect
│ │ ├── __Override.php
│ │ ├── __Override.php.expect
│ │ ├── attributes.php
│ │ └── attributes.php.expect
│ ├── Basic_Concepts/
│ │ ├── .hhconfig
│ │ ├── program_structure.php
│ │ ├── program_structure.php.expectf
│ │ ├── top_level_stuff.php
│ │ └── top_level_stuff.php.expect
│ ├── Classes/
│ │ ├── .hhconfig
│ │ ├── Aircraft.php
│ │ ├── Aircraft.php.expect
│ │ ├── Closure_call.php
│ │ ├── Closure_call.php.expectf
│ │ ├── Generator_getReturn.php
│ │ ├── Generator_getReturn.php.expectf
│ │ ├── MathLibrary.php
│ │ ├── MathLibrary.php.expect
│ │ ├── MathLibrary_test1.php
│ │ ├── MathLibrary_test1.php.expect
│ │ ├── MyCollection.php
│ │ ├── MyCollection.php.expect
│ │ ├── MyList.php
│ │ ├── MyList.php.expect
│ │ ├── PassengerJet.php
│ │ ├── PassengerJet.php.expect
│ │ ├── Point.php
│ │ ├── Point.php.expect
│ │ ├── Point2.php
│ │ ├── Point2.php.expect
│ │ ├── Point_test1.php
│ │ ├── Point_test1.php.expect
│ │ ├── Serializable.php
│ │ ├── Serializable.php.expectf
│ │ ├── Serializable_with_untrusted_data.php
│ │ ├── Serializable_with_untrusted_data.php.expectf
│ │ ├── Vehicle.php
│ │ ├── Vehicle.php.expect
│ │ ├── Vehicle_test1.php
│ │ ├── Vehicle_test1.php.expect
│ │ ├── __PHP_Incomplete_Class.php
│ │ ├── __PHP_Incomplete_Class.php.expect
│ │ ├── abstract_constants.php
│ │ ├── abstract_constants.php.expect
│ │ ├── cc.php
│ │ ├── cc.php.expectf
│ │ ├── classes.php
│ │ ├── classes.php.expect
│ │ ├── cloning.php
│ │ ├── cloning.php.expect
│ │ ├── constructors.php
│ │ ├── constructors.php.expect
│ │ ├── destructors.php
│ │ ├── destructors.php.expect
│ │ ├── dynamic_methods.php
│ │ ├── dynamic_methods.php.expect
│ │ ├── invoke.php
│ │ ├── invoke.php.expect
│ │ ├── property_initializer.php
│ │ ├── property_initializer.php.expect
│ │ ├── require_extends_implements.php
│ │ ├── require_extends_implements.php.expectf
│ │ ├── sleep_and_wakeup.php
│ │ ├── sleep_and_wakeup.php.expectf
│ │ ├── test_for_new_types.php
│ │ ├── test_for_new_types.php.expectf
│ │ ├── type_constants.php
│ │ ├── type_constants.php.expect
│ │ ├── visibility.php
│ │ └── visibility.php.expect
│ ├── Collections/
│ │ ├── .hhconfig
│ │ ├── collections_intrinsics_list.php
│ │ ├── collections_intrinsics_list.php.expect
│ │ ├── collections_operations.php
│ │ ├── collections_operations.php.expect
│ │ ├── vector.php
│ │ └── vector.php.expect
│ ├── Constants/
│ │ ├── .hhconfig
│ │ ├── Testfile.txt
│ │ ├── constants.php
│ │ ├── constants.php.expect
│ │ ├── context_dependent_constants.php
│ │ ├── context_dependent_constants.php.expectf
│ │ ├── core_predefined_constants.php
│ │ └── core_predefined_constants.php.expect
│ ├── Enums/
│ │ ├── .hhconfig
│ │ ├── enum_constraints.php
│ │ ├── enum_constraints.php.expect
│ │ ├── enums.php
│ │ ├── enums.php.expect
│ │ ├── enums_ops.php
│ │ ├── enums_ops.php.expect
│ │ ├── string_int_equality_problem.php
│ │ └── string_int_equality_problem.php.expectf
│ ├── Exception_Handling/
│ │ ├── .hhconfig
│ │ ├── Exception_class.php
│ │ ├── Exception_class.php.expectf
│ │ ├── MyRangeException.php
│ │ ├── MyRangeException.php.expect
│ │ ├── MyRangeException_test1.php
│ │ ├── MyRangeException_test1.php.expectf
│ │ ├── hierarchy_of_exception_classes.php
│ │ ├── hierarchy_of_exception_classes.php.expect
│ │ ├── jump_from_catch_or_finally_clause.php
│ │ ├── jump_from_catch_or_finally_clause.php.expect
│ │ ├── odds_and_ends.php
│ │ ├── odds_and_ends.php.expect
│ │ ├── set_exception_handler.php
│ │ └── set_exception_handler.php.expectf
│ ├── Expressions/
│ │ ├── .hhconfig
│ │ ├── Additive_Operators/
│ │ │ ├── .hhconfig
│ │ │ ├── addition_subtraction_concatenation.php
│ │ │ ├── addition_subtraction_concatenation.php.expect
│ │ │ ├── array_concatenation.php
│ │ │ └── array_concatenation.php.expect
│ │ ├── Binary_Logical_Operators/
│ │ │ ├── .hhconfig
│ │ │ ├── binary_logical_operators.php
│ │ │ └── binary_logical_operators.php.expect
│ │ ├── Bitwise_Shift_Operators/
│ │ │ ├── .hhconfig
│ │ │ ├── bitwise_shift.php
│ │ │ └── bitwise_shift.php.expect
│ │ ├── Bitwise_and_or_xor_Operators/
│ │ │ ├── .hhconfig
│ │ │ ├── bitwise_and_or_xor.php
│ │ │ └── bitwise_and_or_xor.php.expect
│ │ ├── Coalesce Operator/
│ │ │ ├── coalesce.php
│ │ │ └── coalesce.php.expect
│ │ ├── Conditional_Operator/
│ │ │ ├── .hhconfig
│ │ │ ├── conditional.php
│ │ │ └── conditional.php.expect
│ │ ├── Equality_Operators/
│ │ │ ├── .hhconfig
│ │ │ ├── Testfile1.txt
│ │ │ ├── Testfile2.txt
│ │ │ ├── comparisons.php
│ │ │ ├── comparisons.php.expect
│ │ │ ├── equality_comparison_of_objects.php
│ │ │ └── equality_comparison_of_objects.php.expect
│ │ ├── Instanceof_Operator/
│ │ │ ├── .hhconfig
│ │ │ ├── instanceof.php
│ │ │ └── instanceof.php.expect
│ │ ├── Lambda_Expressions/
│ │ │ ├── .hhconfig
│ │ │ ├── lambdas.php
│ │ │ └── lambdas.php.expectf
│ │ ├── Multiplicative_Operators/
│ │ │ ├── .hhconfig
│ │ │ ├── multiplication_division_modulus.php
│ │ │ └── multiplication_division_modulus.php.expect
│ │ ├── Null_safe_method_call/
│ │ │ ├── .hhconfig
│ │ │ ├── null_safe_calls.php
│ │ │ └── null_safe_calls.php.expect
│ │ ├── Pipe_Operator/
│ │ │ ├── pipe.php
│ │ │ └── pipe.php.expect
│ │ ├── Postfix_Operators/
│ │ │ ├── .hhconfig
│ │ │ ├── array_creation.php
│ │ │ ├── array_creation.php.expect
│ │ │ ├── exponentiation.php
│ │ │ ├── exponentiation.php.expect
│ │ │ ├── function_call.php
│ │ │ ├── function_call.php.expect
│ │ │ ├── function_call_with_strict_checking.php
│ │ │ ├── function_call_with_strict_checking.php.expectf
│ │ │ ├── member_selection_operator.php
│ │ │ ├── member_selection_operator.php.expect
│ │ │ ├── new.php
│ │ │ ├── new.php.expect
│ │ │ ├── new_anonymous_classes.php
│ │ │ ├── new_anonymous_classes.php.expectf
│ │ │ ├── nullable_and_arithmetic.php
│ │ │ ├── nullable_and_arithmetic.php.expect
│ │ │ ├── nullsafe_member_selection.php
│ │ │ ├── nullsafe_member_selection.php.expect
│ │ │ ├── post-increment_and_decrement_integer_edge_cases.php
│ │ │ ├── post-increment_and_decrement_integer_edge_cases.php.expect
│ │ │ ├── post_increment_and_decrement.php
│ │ │ ├── post_increment_and_decrement.php.expect
│ │ │ ├── scope_resolution_operator.php
│ │ │ ├── scope_resolution_operator.php.expectf
│ │ │ ├── subscripting.php
│ │ │ ├── subscripting.php.expect
│ │ │ ├── subscripting_2.php
│ │ │ ├── subscripting_2.php.expect
│ │ │ └── subscripting_2.php.expectf
│ │ ├── Primary_Expressions/
│ │ │ ├── .hhconfig
│ │ │ ├── Point.php
│ │ │ ├── Point.php.expect
│ │ │ ├── Point2.php
│ │ │ ├── Point2.php.expect
│ │ │ ├── intrinsics_echo.php
│ │ │ ├── intrinsics_echo.php.expect
│ │ │ ├── intrinsics_exit.php
│ │ │ ├── intrinsics_exit.php.expect
│ │ │ ├── intrinsics_invariant.php
│ │ │ ├── intrinsics_invariant.php.expect
│ │ │ ├── intrinsics_list.php
│ │ │ ├── intrinsics_list.php.expect
│ │ │ ├── listPHP.php
│ │ │ ├── listPHP.php.expect
│ │ │ ├── primary.php
│ │ │ └── primary.php.expect
│ │ ├── Relational_Operators/
│ │ │ ├── .hhconfig
│ │ │ ├── Testfile1.txt
│ │ │ ├── Testfile2.txt
│ │ │ ├── combined_comparison.php
│ │ │ ├── combined_comparison.php.expectf
│ │ │ ├── comparisons.php
│ │ │ ├── comparisons.php.expect
│ │ │ ├── relational_comparison_of_objects.php
│ │ │ └── relational_comparison_of_objects.php.expect
│ │ ├── Testfile.txt
│ │ ├── Unary_Operators/
│ │ │ ├── .hhconfig
│ │ │ ├── cast.php
│ │ │ ├── cast.php.expect
│ │ │ ├── error_control.php
│ │ │ ├── error_control.php.expectf
│ │ │ ├── pre-increment_and_decrement.php
│ │ │ ├── pre-increment_and_decrement.php.expect
│ │ │ ├── pre-increment_and_decrement_integer_edge_cases.php
│ │ │ ├── pre-increment_and_decrement_integer_edge_cases.php.expect
│ │ │ ├── unary_arithmetic_operators.php
│ │ │ └── unary_arithmetic_operators.php.expect
│ │ ├── Yield_Operator/
│ │ │ ├── .hhconfig
│ │ │ ├── yield.php
│ │ │ ├── yield.php.expectf
│ │ │ ├── yield_from.php
│ │ │ └── yield_from.php.expectf
│ │ ├── conversions.php
│ │ ├── conversions.php.expectf
│ │ ├── limits_on_types_in_arithmetic.php
│ │ ├── limits_on_types_in_arithmetic.php.expect
│ │ ├── yield.php
│ │ └── yield.php.expectf
│ ├── Functions/
│ │ ├── .hhconfig
│ │ ├── TestInc.php
│ │ ├── TestInc.php.expect
│ │ ├── anonymous_function_name.php
│ │ ├── anonymous_function_name.php.expect
│ │ ├── anonymous_functions.php
│ │ ├── anonymous_functions.php.expectf
│ │ ├── anonymous_functions2.php
│ │ ├── anonymous_functions2.php.expect
│ │ ├── async_functions.php
│ │ ├── async_functions.php.expectf
│ │ ├── async_functions2.php
│ │ ├── async_functions2.php.expect
│ │ ├── basics.php
│ │ ├── basics.php.expectf
│ │ ├── callable_typehint.php
│ │ ├── callable_typehint.php.expect
│ │ ├── conditionally_defined_function.php
│ │ ├── conditionally_defined_function.php.expectf
│ │ ├── default_arguments.php
│ │ ├── default_arguments.php.expect
│ │ ├── noreturn.php
│ │ ├── noreturn.php.expect
│ │ ├── override_on_return_type.php
│ │ ├── override_on_return_type.php.expect
│ │ ├── recursion.php
│ │ ├── recursion.php.expect
│ │ ├── this_play.php
│ │ ├── this_play.php.expect
│ │ ├── variable_functions.php
│ │ └── variable_functions.php.expect
│ ├── Generics/
│ │ ├── .hhconfig
│ │ ├── Complex.php
│ │ ├── Complex.php.expect
│ │ ├── Complex_test.php
│ │ ├── Complex_test.php.expect
│ │ ├── Interface_Support.php
│ │ ├── Interface_Support.php.expect
│ │ ├── MyVector.php
│ │ ├── MyVector.php.expect
│ │ ├── MyVector_test.php
│ │ ├── MyVector_test.php.expect
│ │ ├── Stack.php
│ │ ├── Stack.php.expect
│ │ ├── Stack_test.php
│ │ ├── Stack_test.php.expect
│ │ ├── constraints.php
│ │ ├── constraints.php.expect
│ │ ├── contravariance_example.php
│ │ ├── contravariance_example.php.expect
│ │ ├── covariance_example.php
│ │ ├── covariance_example.php.expect
│ │ ├── generic_function.php
│ │ ├── generic_function.php.expect
│ │ ├── generics.php
│ │ └── generics.php.expect
│ ├── Interfaces/
│ │ ├── .hhconfig
│ │ ├── MyCollection.php
│ │ ├── MyCollection.php.expect
│ │ ├── MyList.php
│ │ ├── MyList.php.expect
│ │ ├── MyQueue.php
│ │ ├── MyQueue.php.expect
│ │ ├── interface_requirements.php
│ │ ├── interface_requirements.php.expect
│ │ ├── interfaces.php
│ │ ├── interfaces.php.expect
│ │ ├── qq.php
│ │ └── qq.php.expect
│ ├── Lexical_Structure/
│ │ ├── .hhconfig
│ │ ├── Tokens/
│ │ │ ├── .hhconfig
│ │ │ ├── array_literals.php
│ │ │ ├── array_literals.php.expect
│ │ │ ├── heredoc_string_literals.php
│ │ │ ├── heredoc_string_literals.php.expect
│ │ │ ├── integer_literals_edge_cases.php
│ │ │ ├── integer_literals_edge_cases.php.expect
│ │ │ ├── name_case_sensitivity.php
│ │ │ ├── name_case_sensitivity.php.expectf
│ │ │ ├── names.php
│ │ │ ├── names.php.expect
│ │ │ ├── nowdoc_string_literals.php
│ │ │ ├── nowdoc_string_literals.php.expect
│ │ │ ├── string_literals.php
│ │ │ ├── string_literals.php.expect
│ │ │ ├── unicode_escape_sequences.php
│ │ │ └── unicode_escape_sequences.php.expect
│ │ ├── comments.php
│ │ ├── comments.php.expect
│ │ ├── keywords.php
│ │ └── keywords.php.expect
│ ├── Namespaces/
│ │ ├── .hhconfig
│ │ ├── Circle.php
│ │ ├── Circle.php.expect
│ │ ├── Point.php
│ │ ├── Point.php.expect
│ │ ├── namespaces1.php
│ │ ├── namespaces1.php.expect
│ │ ├── namespaces2.php
│ │ ├── namespaces2.php.expectf
│ │ ├── namespaces2_test.php
│ │ ├── namespaces2_test.php.expectf
│ │ ├── use_groups.php
│ │ ├── use_groups.php.expectf
│ │ ├── use_groups_require_file.php
│ │ ├── use_groups_require_file.php.expect
│ │ ├── using_namespaces_1.php
│ │ ├── using_namespaces_1.php.expect
│ │ ├── using_namespaces_3.php
│ │ ├── using_namespaces_3.php.expect
│ │ ├── using_namespaces_3_test.php
│ │ └── using_namespaces_3_test.php.expect
│ ├── Nullable_Types/
│ │ ├── .hhconfig
│ │ ├── conversions.php
│ │ ├── conversions.php.expectf
│ │ ├── nullables.php
│ │ └── nullables.php.expect
│ ├── Script_Inclusion/
│ │ ├── .hhconfig
│ │ ├── Circle.php
│ │ ├── Circle.php.expect
│ │ ├── Point.php
│ │ ├── Point.php.expect
│ │ ├── Positions.php
│ │ ├── Positions.php.expect
│ │ ├── limits.php
│ │ ├── limits.php.expect
│ │ ├── mycolors.php
│ │ ├── mycolors.php.expect
│ │ ├── require.php
│ │ ├── require.php.expectf
│ │ ├── require_once.php
│ │ ├── require_once.php.expectf
│ │ ├── return_none.php
│ │ ├── return_none.php.expect
│ │ ├── return_with_value.php
│ │ └── return_with_value.php.expect
│ ├── Serialization/
│ │ ├── .hhconfig
│ │ ├── Point.php
│ │ ├── Point.php.expectf
│ │ ├── serialize.php
│ │ └── serialize.php.expectf
│ ├── Shapes/
│ │ ├── .hhconfig
│ │ ├── shapes.php
│ │ ├── shapes.php.expect
│ │ ├── shapes_rf.php
│ │ └── shapes_rf.php.expect
│ ├── Statements/
│ │ ├── .hhconfig
│ │ ├── Iteration/
│ │ │ ├── .hhconfig
│ │ │ ├── do.php
│ │ │ ├── do.php.expect
│ │ │ ├── for.php
│ │ │ ├── for.php.expect
│ │ │ ├── foreach.php
│ │ │ ├── foreach.php.expect
│ │ │ ├── while.php
│ │ │ └── while.php.expect
│ │ ├── Jump/
│ │ │ ├── .hhconfig
│ │ │ ├── break.php
│ │ │ ├── break.php.expect
│ │ │ ├── continue.php
│ │ │ └── continue.php.expect
│ │ ├── Selection/
│ │ │ ├── .hhconfig
│ │ │ ├── if.php
│ │ │ ├── if.php.expectf
│ │ │ ├── switch.php
│ │ │ └── switch.php.expect
│ │ ├── expression_statement.php
│ │ └── expression_statement.php.expect
│ ├── Traits/
│ │ ├── .hhconfig
│ │ ├── trait_implements_interface.php
│ │ ├── trait_implements_interface.php.expect
│ │ ├── trait_requirements.php
│ │ ├── trait_requirements.php.expect
│ │ ├── traits.php
│ │ └── traits.php.expect
│ ├── Tuples/
│ │ ├── .hhconfig
│ │ ├── tuples.php
│ │ └── tuples.php.expect
│ ├── Types/
│ │ ├── .hhconfig
│ │ ├── Issue_109.php
│ │ ├── Issue_109.php.expectf
│ │ ├── Issue_110.php
│ │ ├── Issue_110.php.expect
│ │ ├── Testfile.txt
│ │ ├── arraykey.php
│ │ ├── arraykey.php.expect
│ │ ├── arrays.php
│ │ ├── arrays.php.expectf
│ │ ├── arrays2.php
│ │ ├── arrays2.php.expectf
│ │ ├── bool.php
│ │ ├── bool.php.expect
│ │ ├── classname.php
│ │ ├── classname.php.expect
│ │ ├── closure.php
│ │ ├── closure.php.expect
│ │ ├── determined_type.php
│ │ ├── determined_type.php.expect
│ │ ├── enum.php
│ │ ├── enum.php.expect
│ │ ├── float.php
│ │ ├── float.php.expect
│ │ ├── int.php
│ │ ├── int.php.expect
│ │ ├── mixed.php
│ │ ├── mixed.php.expect
│ │ ├── nullables.php
│ │ ├── nullables.php.expect
│ │ ├── num.php
│ │ ├── num.php.expect
│ │ ├── numeric_like_strings.php
│ │ ├── numeric_like_strings.php.expect
│ │ ├── numeric_strings.php
│ │ ├── numeric_strings.php.expect
│ │ ├── resources.php
│ │ ├── resources.php.expectf
│ │ ├── scalar_general.php
│ │ ├── scalar_general.php.expectf
│ │ ├── shape_specific_functions.php
│ │ ├── shape_specific_functions.php.expect
│ │ ├── shape_subtyping.php
│ │ ├── shape_subtyping.php.expect
│ │ ├── shapes.php
│ │ ├── shapes.php.expect
│ │ ├── shapes.php.expectf
│ │ ├── shapes2.php
│ │ ├── shapes2.php.expectf
│ │ ├── shapes_rf.php
│ │ ├── shapes_rf.php.expect
│ │ ├── string.php
│ │ ├── string.php.expect
│ │ ├── this.php
│ │ ├── this.php.expectf
│ │ ├── tuple.php
│ │ ├── tuple.php.expect
│ │ ├── type_aliases.php
│ │ ├── type_aliases.php.expectf
│ │ ├── type_aliases_rf.php
│ │ ├── type_aliases_rf.php.expectf
│ │ ├── type_inferencing.php
│ │ ├── type_inferencing.php.expect
│ │ ├── type_side_effects.php
│ │ ├── type_side_effects.php.expect
│ │ ├── void.php
│ │ └── void.php.expect
│ └── Variables/
│ ├── .hhconfig
│ ├── placeholder_variable.php
│ ├── placeholder_variable.php.expect
│ ├── predefined_variables.php
│ ├── predefined_variables.php.expect
│ ├── variable_kinds.php
│ └── variable_kinds.php.expect
└── tools/
├── README.md
├── add_hh_fixme_to_tests.php
├── add_language_to_code_blocks.php
├── create_test_expect_files.php
├── split.php
├── toc.php
└── xreference/
├── README.md
├── section_map.csv
└── xreference.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.DS_Store
www.pid
.commit-template
*.php.diff
*.php.out
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Code of Conduct
Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please [read the full text](https://code.fb.com/codeofconduct) so that you can understand what actions will and will not be tolerated.
================================================
FILE: CONTRIBUTING.md
================================================
## Contributing to the Specification for Hack
We'd love your help in improving, correcting, adding to the specification.
Please [file an issue](https://github.com/hhvm/hack-langspec/issues/) or submit a
pull request at the [spec git repo](https://github.com/hhvm/hack-langspec).
## License for your Contributions
Any contribution you provide to the Specification for Hack must adhere to the
same license as stated in the [LICENSE](LICENSE).
================================================
FILE: FORMATTING.md
================================================
# Formatting rules
1. The format of the Hack Language Specification is
[Markdown](http://daringfireball.net/projects/markdown/).
2. Everything in the actual specification document must be ASCII only.
3. The only allowed extensions to original Markdown are tables and code blocks
(indicated by three backticks).
4. Style
* Use spaces to indent, not tabs.
* For headings, use prefixed hash symbols `# Example`, not underlining it
with `===`.
* Use of *inline* links `[example](http://example.org)` is preferred over
*reference* links `[example][xmpl]` unless used multiple times in a
paragraph or section. This is to allow for easier splitting and
reorganization of the document.
* Try to stick to 80 chars wide, if possible. This is not as strict as
in coding standard rules, but still easier to read most of the times.
This does only apply to text, not to code examples or tables.
================================================
FILE: LICENSE
================================================
Facebook has dedicated all copyright to this specification to the public
domain worldwide under the CC0 Public Domain Dedication located at
argument:
a value passed to a function, that is intended to map to a
corresponding parameter.
behavior:
external appearance or action.
behavior, implementation-defined:
behavior specific to an implementation, where that implementation
must document that behavior.
behavior, undefined:
behavior which is not guaranteed to
produce any specific result. Usually follows an erroneous program
construct or data.
behavior, unspecified:
behavior for which this specification provides no requirements.
case-preserved:
a construct which is case-insensitive upon declaration, but
case-sensitive upon subsequent usage.
constraint:
restriction, either syntactic or semantic, on how language elements
can be used.
error, fatal:
a translation or runtime condition from which the translator or
engine cannot recover.
error, fatal, catchable:
a fatal error that can be caught by a user-defined handler.
error, non-fatal:
an error that is not fatal.
lvalue:
an expression that designates a memory location having a type.
lvalue, modifiable:
an lvalue whose value can be changed.
lvalue, non-modifiable:
an lvalue whose value cannot be changed.
parameter:
a variable declared in the parameter list of a function that is
intended to map to a corresponding argument in a call to that
function.
Hack Run-Time Engine:
the machinery that executes a Hack program. Referred to as *the
Engine* throughout this specification.
value:
precise meaning of the contents of a memory location when
interpreted as having a specific type.
Other terms are defined throughout this specification, as needed, with
the first usage being typeset *like this*.
================================================
FILE: spec/04-basic-concepts.md
================================================
# Basic Concepts
## Program Structure
A Hack *program* consists of one or more source files, known formally as
*scripts*.
script: <?hh // strict declaration-listopt declaration-list: declaration declaration-list declaration declaration: inclusion-directive enum-declaration function-definition class-declaration interface-declaration trait-declaration namespace-definition namespace-use-declaration alias-declaration**Defined elsewhere** * [*alias-declaration*](05-types.md#type-aliases) * [*class-declaration*](16-classes.md#class-declarations) * [*enum-declaration*](13-enums.md#enum-declarations) * [*function-definition*](15-functions.md#function-definitions) * [*inclusion-directive*](12-script-inclusion.md#general) * [*interface-declaration*](17-interfaces.md#interface-declarations) * [*namespace-definition*](20-namespaces.md#defining-namespaces) * [*namespace-use-declaration*](20-namespaces.md#namespace-use-declarations) * [*trait-declaration*](18-traits.md#trait-declarations) A Hack script can be processed in any one of a number of *modes*, of which `strict` is one. This mode is specified in a [*special single-line-comment*](09-lexical-structure.md#comments), on the first source line, as shown. This comment may be separated from the preceding <?hh by an arbitrary amount of [horizontal white space](09-lexical-structure.md#white-space), which must not include any [*delimited-comments*](09-lexical-structure.md#comments). This specification is written from the perspective of strict mode only. A conforming implementation may provide modes other than `strict`, but they are outside the scope of this specification. A script can import another script via [script inclusion](12-script-inclusion.md#script-inclusion-operators). The top level of a script is simply referred to as the *top level*. ## Program Start-Up Once the start-up function begins execution, it is implementation-defined as to whether it has access to things like command-line arguments and environment variables. [PHP's global variables `$argc` and `$argv` are not available in `strict` mode.] ## Program Termination A program may terminate normally in the following ways: - A [`return` statement](11-statements.md#the-return-statement) in the start-up function is executed. - The intrinsic [`exit`](10-expressions.md#exit) is called explicitly. The behavior of the first case is equivalent to corresponding calls to `exit`. A program may terminate abnormally under various circumstances, such as the detection of an uncaught exception, or the lack of memory or other critical resource. If execution reaches the end of the start-up script via a fatal error, or via an uncaught exception and there is no uncaught exception handler registered by `set_exception_handler`, that is equivalent to `exit(255)`. If execution reaches the end of the start-up script via an uncaught exception and an uncaught exception handler was registered by `set_exception_handler`, that is equivalent to exit(0). It is unspecified whether [object destructors](16-classes.md#destructors) are run. In all other cases, the behavior is unspecified. ## The Memory Model ### General This section and those immediately following it describe the abstract memory model used by Hack for storing variables. A conforming implementation may use whatever approach is desired as long as from any testable viewpoint it appears to behave as if it follows this abstract model. The abstract model makes no explicit or implied restrictions or claims about performance, memory consumption, and machine resource usage. The abstract model presented here defines three kinds of abstract memory locations: - A *value storage location* (VStore) is used to represent a program value, and is created by the Engine as needed. A VStore can contain a scalar value such as an integer or a Boolean, or it can contain a handle pointing to an HStore (see below). - A *variable slot* (VSlot) is used to represent a variable named by the programmer in the source code, such as a local variable, an array element, an instance property of an object, or a static property of a class. A VSlot comes into being based on explicit usage of a variable in the source code. A VSlot contains a pointer to a VStore. - A *heap storage location* (HStore) is used to represent the contents of any non-scalar value, and is created by the Engine as needed. Each existing variable has its own VSlot, which at any time contains a pointer to a VStore. A VSlot cannot contain a null pointer. A VSlot can be changed to point to different VStores over time. Multiple VSlots may simultaneously point to the same VStore. When a new VSlot is created, a new VStore is also created and the VSlot is initially set to point to the new VStore. A VStore can be changed to contain different scalar values and handles over time. Multiple VStores may simultaneously contain handles that point to the same HStore. When a VStore is created it initially contains the scalar value `null` unless specified otherwise. In addition to containing a value, VStores also carry a *type tag* that indicates the [type](05-types.md#types) of the VStore’s value. A VStore’s type tag can be changed over time. At any given time a VStore’s type tag may be one of the following: `Null`, `Bool`, `Int`, `Float`, `Str`, `Arr`, `Arr-D` (see [§§](#deferred-array-copying)), `Obj`, or `Res`. An HStore represents the contents of a non-scalar value, and it may contain zero or more VSlots. At run time, the Engine may add new VSlots and it may remove and destroy existing VSlots as needed to support adding/removing array elements (for arrays) and to support adding/removing instance properties (for objects). HStores that represent the contents of arrays and objects have some unspecified way to identify and retrieve a contained VSlot using a dictionary scheme (such as having values with integer keys or case-sensitive string keys). Whether an HStore is a fixed-size during its whole lifetime or whether it can change size, is unspecified. Whether it allocates auxiliary chunks of memory or not, is unspecified. Whether it organizes it's contained VSlots in a linked list or some other manner is unspecified. An HStore’s VSlots (i.e., the VSlots contained within the HStore) point to VStores, and each VStore contains a scalar value or a handle to an HStore, and so on through arbitrary levels, allowing arbitrarily complex data structures to be represented. For example, a singly linked list might consist of a variable called `$root`, which is represented by a VSlot pointing to a VStore containing a handle to the first node. Each node is represented by an HStore that contains the data for that node in one or more VSlots, as well as a VSlot pointing to VStore containing a handle to the next node. Similarly, a binary tree might consist of a variable called `$root`, which is represented by a VSlot pointing to a VStore containing a handle to the root node. Each node is represented by an HStore that contains the data for that node in one or more VSlots, as well as a pair of VSlots pointing to VStores containing the handles to the left and right branch nodes. The leaves of the tree would be VStores or HStores, as needed. VSlots cannot contain pointers to VSlots or handles to HStores. VStores cannot contain pointers to VSlots or VStores. HStores cannot directly contain any pointers or handles to any abstract memory location; HStores can only directly contain VSlots. Here is an example demonstrating one possible arrangement of VSlots, VStores, and HStores:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]] | | V V [VStore Int 1] [VStore Int 3]In this picture the VSlot in the upper left corner represents the variable `$a`, and it points to a VStore that represents `$a`’s current value. This VStore contains a handle to an HStore which represents the contents of an object of type Point with two instance properties `$x` and `$y`. This HStore contains two VSlots representing instance properties `$x` and `$y`, and each of these VSlots points to a distinct VStore which contains an integer value. ***Implementation Notes*** A concrete implementation of Hack may be mapped roughly onto the abstract memory model as follows: `zval pointer => VSlot, zval => VStore, HashTable => HStore`, and `zend_object/zend_object_handlers => HStore`. Note, however, that the abstract memory model is not intended to exactly match any specific implementation’s model, and for generality and simplicity there may be some superficial differences between the described model and an implementation's model. For most operations, the mapping between VSlots and VStores remains the same. Only the following program constructs can change a VSlot to point to different VStore: the use of `&` in a [`foreach` statement](11-statements.md#the-foreach-statement). ### Reclamation and Automatic Memory Management The Engine is required to manage the lifetimes of VStores and HStores using some form of automatic memory management. When dealing with VStores and HStores, the Engine is required to implement some form of automatic memory management. When a VStore or HStore is created, memory is allocated for it, and for an HStore that represents an [object](05-types.md#class-types), its [constructor](16-classes.md#constructors) is invoked. Later, if a VStore or HStore becomes unreachable through any existing variable, they become eligible for reclamation to release the memory they occupy. The engine may reclaim a VStore or HStore at any time between when it becomes eligible for reclamation and when the script exits. Before reclaiming an HStore that represents an [object](05-types.md#class-types), the Engine will invoke the object’s [destructor](16-classes.md#destructors) if one is defined. The Engine must reclaim each VSlot when the [storage duration](#storage-duration) of its corresponding variable ends, when the variable is explicitly unset by the programmer, or when the script exits, whichever comes first. In the case where a VSlot is contained within an HStore (i.e. an array element or an object instance property), the engine must immediate reclaim the VSlot when it is explicitly unset by the programmer, when the containing HStore is reclaimed, or when the script exits, whichever comes first. The precise form of automatic memory management used by the Engine is unspecified, which means that the time and order of the reclamation of VStores and HStores is unspecified. A VStore’s refcount is defined as the number of unreclaimed VSlots that point to the VStore. Because the precise form of automatic memory management is not specified, a VStore’s refcount at a given time may differ between conforming implementations due to VSlots, VStores, and HStores being reclaimed at different times. Despite the use of the term refcount, conforming implementations are not required to use a reference counting-based implementation for automatic memory management. ### Assignment #### General This section and those immediately following it describe the abstract model’s implementation of *value assignment* and *byRef assignment*. Value assignment of non-array types to local variables is described first, followed by byRef assignment with local variables, followed by value assignment of array types to local variables, and ending with value assignment with complex left-hand side expressions, and byRef assignment with complex expressions on the left- or right-hand side. Value assignment and byRef assignment are core to HHVM, the Engine which supports the PHP and Hack languages. Many other operations in the PHP and Hack specification are described in terms of value assignment. On the other hand, byRef assignment is used only by PHP, not by Hack. However, a discussion of such assignment has been retained here for historical reference. #### Value Assignment of Scalar Types to a Local Variable Value assignment is the primary means by which the programmer can create local variables. If a local variable appears on the left-hand side of value assignment does not exist, the engine will bring a new local variable into existence and create a VSlot and initial VStore for storing the local variable’s value. Consider the following example of [value assignment](10-expressions.md#simple-assignment) of scalar values to local variables: ```Hack $a = 123; $b = false; ```
[VSlot $a *]-->[VStore Int 123] [VSlot $b *]-->[VStore Bool false]Variable `$a` comes into existence and is represented by a newly created VSlot pointing to a newly created VStore. Then the integer value 123 is written to the VStore. Next, `$b` comes into existence represented by a VSlot and corresponding VStore, and the Boolean value false is written to the VStore. Next consider the value assignment `$b = $a`:
[VSlot $a *]-->[VStore Int 123] [VSlot $b *]-->[VStore Int 123 (Bool false was overwritten)]The integer value 123 is read from `$a`’s VStore and is written into `$b`’s VStore, overwriting its previous contents. As we can see, the two variables are completely self-contained; each has its own VStore containing a separate copy of the integer value 123. Value assignment reads the contents of one VStore and overwrites the contents of the other VStore, but the relationship of VSlots to VStores remains unchanged. Changing the value of `$b` has no effect on `$a`, and vice versa. Using literals or arbitrarily complex expressions on the right hand side of value assignment value works the same as it does for variables, except that the literals or expressions don’t have their own VSlots or VStores. The scalar value or handle produced by the literal or expression is written into the VStore of the left hand side, overwriting its previous contents. ***Implementation Notes*** For simplicity, the abstract model’s definition of value assignment never changes the mapping from VSlots to VStores. This aspect of the abstract model is superficially different from the php.net implementation’s model, which in some cases will set two variable slots to point to the same zval when performing value assignment. Despite this superficial difference, php.net’s implementation produces the same observable behavior as the abstract model presented here. To illustrate the semantics of value assignment further, consider `++$b`:
[VSlot $a *]-->[VStore Int 123] [VSlot $b *]-->[VStore Int 124 (123 was overwritten)]Now consider `$a = 99`:
[VSlot $a *]-->[VStore Int 99 (123 was overwritten)] [VSlot $b *]-->[VStore Int 124]In both of these examples, one variable’s value is changed without affecting the other variable’s value. While the above examples only demonstrate value assignment for integer and Boolean values, the same mechanics apply for all scalar types. Note that strings are also considered scalar values for the purposes of the abstract memory model. Unlike non-scalar types which are represented using a VStore pointing to an HStore containing the non-scalar value’s contents, the abstract model assumes that a string’s entire contents (i.e., the string’s characters and its length) can be stored in a VStore and that value assignment for a string eagerly copies a string’s entire contents to the VStore being written to. Consider the following example: ```Hack $a = 'gg'; $b = $a; ```
[VSlot $a *]-->[VStore Str 'gg'] [VSlot $b *]-->[VStore Str 'gg']`$a`’s string value and `$b`’s string values are distinct from each other, and mutating `$a`’s string will not affect `$b`. Consider `++$b`, for example:
[VSlot $a *]-->[VStore Str 'gg'] [VSlot $b *]-->[VStore Str 'gh']***Implementation Notes*** For simplicity, the abstract model represents a string as a scalar value that can be entirely contained within VStore. This aspect of the abstract model is superficially different from the php.net implementation’s model, where a zval points to a separate buffer in memory containing a string’s characters and in the common case multiple slots point to the same zval that holds the string. Despite this superficial difference, php.net’s implementation produces the same observable behavior (excluding performance and resource consumption) as the abstract model presented here. Because a string’s content can be arbitrarily large, copying a string’s entire contents for value assignment can be expensive. In practice an application written in Hack may rely on value assignment of strings being relatively inexpensive (in order to deliver acceptable performance), and as such it is common for an implementation to use a deferred copy mechanism to reduce the cost of value assignment for strings. Deferred copy mechanisms work by not copying a string during value assignment and instead allowing multiple variables to share the string’s contents indefinitely until a mutating operation (such as the increment operator) is about to be executed on the string, at which time some or all of the string’s contents are copied. A conforming implementation may choose to defer copying a string’s contents for value assignment so long as it has no observable effect on behavior from any testable viewpoint (excluding performance and resource consumption). #### Value Assignment of Object and Resource Types to a Local Variable To demonstrate value assignment of objects to local variables, consider the case in which we have a Point class that supports a two-dimensional Cartesian system. An instance of Point contains two instance properties, `$x` and `$y`, that store the x- and y-coordinates, respectively. A [constructor call](14-classes.md#constructors) of the form `Point(x, y)` used with [operator `new`](10-expressions.md#the-new-operator) creates a new point at the given location, and a method call of the form `move(newX, newY)` moves a `Point` to the new location. With the `Point` class, let us consider the value assignment `$a = new Point(1, 3)`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]] | | V V [VStore Int 1] [VStore Int 3]Variable `$a` is given its own VSlot, which points to a VStore that contains a handle pointing to an HStore allocated by [`new`](10-expressions.md#the-new-operator) and that is initialized by `Point`'s constructor. Now consider the value assignment `$b = $a`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]] ^ | | | V V [VSlot $b *]-->[VStore Obj *]-----+ [VStore Int 1] [VStore Int 3]`$b`‘s VStore contains a handle that points to the same object as does `$a`‘s VStore’s handle. Note that the Point object itself was not copied, and note that `$a`’s and `$b`’s VSlots point to distinct VStores. Let's modify the value of the Point whose handle is stored in `$b` using `$b->move(4, 6)`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]] ^ | | | V V [VSlot $b *]-->[VStore Obj *]-----+ [VStore Int 4] [VStore Int 6] (1 was overwritten) (3 was overwritten)As we can see, changing `$b`'s Point changes `$a`'s as well. Now, let's make `$a` point to a different object using `$a = new Point(2, 1)`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]] | | [VSlot $b *]-->[VStore Obj *]-----+ V V | [VStore Int 2] [VStore Int 1] V [HStore Point [VSlot $x *] [VSlot $y *]] | | V V [VStore Int 4] [VStore Int 6]Before `$a` can take on the handle of the new `Point`, its handle to the old `Point` must be removed, which leaves the handles of `$a` and `$b` pointing to different Points. We can remove all these handles using `$a = null` and `$b = null`:
[VSlot $a *]-->[VStore Null] [HStore Point [VSlot $x *] [VSlot $y *] (dead)] | | [VSlot $b *]-->[VStore Null] [VStore Int 2 (dead)]<--+ V [VStore Int 1 (dead)] [HStore Point [VSlot $x *] [VSlot $y *] (dead)] | | [VStore Int 4 (dead)]<--+ V [VStore Int 6 (dead)]By assigning null to `$a`, we remove the only handle to `Point(2,1)`, which allows that object's [destructor](14-classes.md#destructors) to run. A similar thing happens with `$b`, as it too is the only handle to its Point. Although the examples above only show with only two instance properties, the same mechanics apply for value assignment of all object types, even though they can have an arbitrarily large number of instance properties of arbitrary type. Likewise, the same mechanics apply to value assignment of all resource types. #### ByRef Assignment for Scalar Types with Local Variables Let's begin with the same [value assignment](10-expressions.md#simple-assignment) as in the previous section, `$a = 123` and `$b = false`:
[VSlot $a *]-->[VStore Int 123] [VSlot $b *]-->[VStore Bool false]Now consider the [byRef assignment](10-expressions.md#byref-assignment) `$b =& $a`, which has byRef semantics:
[VSlot $a *]-->[VStore Int 123] ^ | [VSlot $b *]-----+ [VStore Bool false (dead)]In this example, byRef assignment changes `$b`’s VSlot point to the same VStore that `$a`’s VSlot points to. The old VStore that `$b`’s VSlot used to point to is now unreachable. As stated in [§§](#general), it is not possible for a VSlot to point to another VSlot, so `$b`‘s VSlot cannot point to `$a`‘s VSlot. When multiple variables’ VSlots point to the same VStore, the variables are said to be *aliases* of each other or they are said to have an *alias relationship*. In the example above, after the byRef assignment executes the variables `$a` and `$b` will be aliases of each other. Now, let's observe what happens when we change the value of `$b` using `++$b`:
[VSlot $a *]-->[VStore Int 124 (123 was overwritten)] ^ | [VSlot $b *]-----+`$b`‘s value, which is stored in the VStore that `$b`’s VSlot points, is changed to 124. And as that VStore is also aliased by `$a`’s VSlot, the value of `$a` is also 124. Indeed, any variable’s VSlot that is aliased to that VStore will have the value 124. Now consider the value assignment `$a = 99`:
[VSlot $a *]-->[VStore Int 99 (124 was overwritten)] ^ | [VSlot $b *]-----+The alias relationship between `$a` and `$b` can be broken explicitly by using `unset` on variable `$a` or variable `$b`. For example, consider `unset($a)`:
[VSlot $a (dead)] [VStore Int 99] ^ | [VSlot $b *]-------------+Unsetting `$a` causes variable `$a` to be destroyed and its corresponding alias to the VStore to be removed, leaving `$b`’s VSlot as the only pointer remaining to the VStore. Other operations can also break an alias relationship between two or more variables. For example, `$a = 123` and `$b =& $a`, and `$c = 'hi'`:
[VSlot $a *]-->[VStore Int 123] ^ | [VSlot $b *]-----+ [VSlot $c *]-->[VStore Str 'hi']After the byRef assignment, `$a` and `$b` now have an alias relationship. Next, let's observe what happens for `$b =& $c`:
[VSlot $a *]-->[VStore Int 123] [VSlot $b *]-----+ | V [VSlot $c *]-->[VStore Str 'hi']As we can see, the byRef assignment above breaks the alias relationship between `$a` and `$b`, and now `$b` and `$c` are aliases of each other. When byRef assignment changes a VSlot to point to a different VStore, it breaks any existing alias relationship the left hand side variable had before the assignment operation. It is also possible to use byRef assignment to make three or more VSlots point to the same VStore. Consider the following example: ```Hack $b =& $a; $c =& $b; $a = 123; ```
[VSlot $a *]-->[VStore Int 123] ^ ^ | | [VSlot $b *]-----+ | | [VSlot $c *]---------+Like value assignment, byRef assignment provides a means for the programmer to created variables. If the local variables that appear on the left- or right-hand side of byRef assignment do not exist, the engine will bring new local variables into existence and create a VSlot and initial VStore for storing the local variable’s value. Note that literals, constants, and other expressions that don’t designate a modifiable lvalue cannot be used on the left- or right-hand side of byRef assignment. #### Byref Assignment of Non-Scalar Types with Local Variables byRef assignment of non-scalar types works using the same mechanism as byRef assignment for scalar types. Nevertheless, it is worthwhile to describe a few examples to clarify the semantics of byRef assignment. Recall the example from [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable)) using the `Point` class: `$a = new Point(1, 3);`
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]] | | V V [VStore Int 1] [VStore Int 3]Now consider the [byRef assignment](10-expressions.md#byref-assignment) `$b =& $a`, which has byRef semantics:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *][VSlot $y *]] ^ | | | V V [VSlot $b *]-----+ [VStore Int 1] [VStore Int 3]`$a` and `$b` now aliases of each other. Note that byRef assignment produces a different result than `$b = $a` where `$a` and `$b` would point to distinct VStores pointing to the same HStore. Let's modify the value of the `Point` aliased by `$a` using `$a->move(4, 6)`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] VSlot $y *]] ^ | | | V V [VSlot $b *]-----+ [VStore Int 4] [VStore Int 6] (1 was overwritten) (3 was overwritten)Now, let's change `$a` itself using the value assignment `$a = new Point(2, 1)`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *][VSlot $y *]] ^ | | | V V [VSlot $b *]-----+ [VStore Int 2] [VStore Int 1] [HStore Point [VSlot $x *] [VSlot $y *] (dead)] | | V V [VStore Int 4 (dead)] [VStore Int 6 (dead)]As we can see, `$b` continues to have an alias relationship with `$a`. Here's what's involved in that assignment: `$a` and `$b`'s VStore’s handle pointing to `Point(4,6)` is removed, `Point(2,1)` is created, and `$a` and `$b`’s VStore is overwritten to contain a handle pointing to that new `Point`. As there are now no VStores pointing to `Point(4,6)`, its [destructor](14-classes.md#destructors) can run. We can remove these aliases using `unset($a, $b)`:
[VSlot $a (dead)] [HStore Point [VSlot $x *] [VSlot $y *] (dead)] | | V V [VSlot $b (dead)] [VStore Int 2 (dead)] [VStore Int 1 (dead)]Once all the aliases to the VStores are gone, the VStores can be destroyed, in which case, there are no more pointers to the HStore, and its [destructor](16-classes.md#destructors) can be run. #### Value Assignment of Array Types to Local Variables The semantics of value assignment of array types is different from value assignment of other types. Recall the `Point` class from the examples in [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable), and consider the following [value assignments](10-expressions.md#simple-assignment) and their abstract implementation: `$a = array(10, 'B' => new Point(1, 3));`
[VSlot $a *]-->[VStore Arr *]-->[HStore Array [VSlot 0 *] [VSlot 'B' *]] | | V V [VStore Int 10] [VStore Obj *] | [HStore Point [VSlot $x *] [VSlot $y *]]<--+ | | V V [VStore Int 1] [VStore Int 3]In the example above, `$a`‘s VStore is initialized to contain a handle to an HStore for an array containing two elements, where one element is an integer and the other is a handle to an HStore for an object. Now consider the following value assignment `$b = $a`. A conforming implementation must implement value assignment of arrays in one of the following ways: (1) eager copying, where the implementation makes a copy of `$a`’s array during value assignment and changes `$b`’s VSlot to point to the copy; or (2) deferred copying, where the implementation uses a deferred copy mechanism that meets certain requirements. This section describes eager copying, and the section that immediately follows ([§§](#deferred-array-copying)) describes deferred copying. To describe the semantics of eager copying, let’s begin by considering the value assignment `$b = $a`:
[VSlot $a *]-->[VStore Arr *]-->[HStore Array [VSlot 0 *] [VSlot 'B' *]] | | [VSlot $b *]-->[VStore Arr *] V V | [VStore Int 10] [VStore Obj *] V | [HStore Array [VSlot 0 *] [VSlot 'B' *]] | | | | +---------+ +---------+ | V V | [VStore Int 10] [VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]]<---+ | | V V [VStore Int 1] [VStore Int 3]The value assignment `$b = $a` made a copy of `$a`’s array. Note how `$b`’s VSlot points to a different VStore than `$a`’s VSlot, and `$b`’s VStore points to a different HStore than `$b`’s VStore. Each source array element is copied using *member-copy assignment* `=*`, which is defined as follows: ```Hack $destination =* $source ``` - If `$source`’s VStore has a refcount equal to 1, the Engine copies the array element using value assignment (`destination = $source`). - If `$source`’s VStore has a refcount that is greater than 1, the Engine uses an implementation-defined algorithm to decide whether to copy the element using value assignment (`$destination = $source`) or byRef assignment (`$destination =& $source`). Note the member-copy assignment `=*` is **not** an operator or language construct in the Hack language, but instead it is used internally to describe behavior for the engine for array copying and other operations For the particular example above, member-copy assignment exhibits the same semantics as value assignment for all conforming implementations because all of the array elements’ VStores have a refcount equal to 1. The first element VSlots in `$a`’s array and `$b`’s array point to distinct VStores, each of which contain a distinct copy of the integer value 10. The second element VSlots in `$a`’s array and `$b`’s array point to distinct VStores, each of which contain a handle to the same object HStore. Let’s consider another example: ```Hack $x = 123; $a = array(array(&$x, 'hi')); $b = $a; ``` Eager copying can produce two possible outcomes depending on the implementation. Here is the first possible outcome:
[VSlot $a *]---->[VStore Arr *]---->[HStore Array [VSlot 0 *]] | [VSlot $x *]-------------------------+ [VStore Arr *]<---+ | | [VSlot $b *]-->[VStore Arr *] | V | | [HStore Array [VSlot 0 *][VSlot 1 *]] V | | | [HStore Array [VSlot 0 *]] | V | | +---------------->[VStore Int 123] | V ^ V [VStore Arr *] | [VStore Str 'hi'] | +--------------+ V | [HStore Array [VSlot 0 *] [VSlot 1 *]] | V [VStore Str 'hi']Here is the second possible outcome:
[VSlot $a *]---->[VStore Arr *]---->[HStore Array [VSlot 0 *]] | [VSlot $x *]-------------------------+ [VStore Arr *]<----+ | | [VSlot $b *]-->[VStore Arr *] | V | | [HStore Array [VSlot 0 *] [VSlot 1 *]] V | | | [HStore Array [VSlot 0 *]] | V | | +---------------->[VStore Int 123] | V V [VStore Arr *] [VStore Str 'hi'] | V [HStore Array [VSlot 0 *] [VSlot 1 *]] | | V V [VStore Int 123] [VStore Str 'hi']In both possible outcomes, value assignment with eager copying makes a copy of `$a`’s array, copying the array’s single element using member-copy assignment (which in this case will exhibit the same semantics of value assignment for all implementations), which in turn makes a copy of the inner array inside `$a`’s array, copying the inner array’s elements using member-copy assignment. The inner array’s first element VSlot points to a VStore that has a refcount that is greater than 1, so an implementation-defined algorithm is used to decide whether to use value assignment or byRef assignment. The first possible outcome shown above demonstrates what happens if the implementation chooses to do byRef assignment, and the second possible outcome shown above demonstrates what happens if the implementation chooses to do value assignment. The inner array’s second element VSlot points to a VStore that has a refcount equal to 1, so value assignment is used to copy the inner array’s second element for all conforming implementations that use eager copying. Although the examples in this section only use arrays with one element or two elements, the model works equally well for all arrays even though they can have an arbitrarily large number of elements. As to how an HStore accommodates all of them, is unspecified and unimportant to the abstract model. #### Deferred Array Copying As mentioned in the previous section ([§§](#value-assignment-of-array-types-to-local-variables)), an implementation may choose to use a deferred copy mechanism instead of eagerly making a copy for value assignment of arrays. An implementation may use any deferred copy mechanism desired so long as it conforms to the abstract model’s description of deferred array copy mechanisms presented in this section. Because an array’s contents can be arbitrarily large, eagerly copying an array’s entire contents for value assignment can be expensive. In practice an application written in Hack may rely on value assignment of arrays being relatively inexpensive for the common case (in order to deliver acceptable performance), and as such it is common for an implementation to use a deferred array copy mechanism in order to reduce the cost of value assignment for arrays. Unlike conforming deferred string copy mechanisms discussed in [§§](#value-assignment-of-scalar-types-to-a-local-variable) that must produce the same observable behavior as eager string copying, deferred array copy mechanisms are allowed in some cases to exhibit observably different behavior than eager array copying. Thus, for completeness this section describes how deferred array copies can be modeled in the abstract memory model and how conforming deferred array copy mechanisms must behave. Conforming deferred array copy mechanisms work by not making an array copy during value assignment, by allowing the destination VStore to share an array HStore with the source VStore, and by making a copy of the array HStore at a later time if or when it is necessary. The abstract model represents a deferred array copy relationship by marking the destination VStore with a special “Arr-D” type tag and by sharing the same array HStore between the source and destination VStores. Note that the source VStore’s type tag remains unchanged. For the purposes of this abstract model, the “Arr-D” type tag is considered identical to the “Arr” type in all respects except when specified otherwise. To illustrate this, let’s see how the previous example would be represented under the abstract model assuming the implementation defers the copying the array: ```Hack $x = 123; $a = array(array(&$x, ‘hi’)); $b = $a; ```
[VSlot $a *]--->[VStore Arr *]--->[HStore Array [VSlot 0 *]] ^ | | [VStore Arr *]<--+ [VSlot $b *]--->[VStore Arr-D *]----+ | V [HStore Array [VSlot 0 *] [VSlot 1 *]] | | V | [VSlot $x *]------------------------------------------>[VStore Int 123] | V [VStore Str 'hi']As we can see, both `$a`’s VStore (the source VStore) and `$b`’s VStore (the destination VStore) point to the same array HStore. Note the asymmetric nature of how deferred array copies are represented in the abstract model. In the above example the source VStore’s type tag remains unchanged after value assignment, whereas the destination VStore’s type tag was changed to “Arr-D”. When the engine is about to perform an array-mutating operation on a VStore tagged “Arr” that participates in a deferred array copy relationship or on a VStore tagged “Arr-D”, the engine must first take certain actions that involve making a copy of the array (described in the next paragraph) before performing the array-mutating operation. An array-mutating operation is any operation can add or remove array elements, overwrite existing array elements, change the state of the array’s internal cursor, or cause the refcount of one or more of the array’s element VStores or subelement VStores to increase from 1 to a value greater than 1. This requirement to take certain actions before performing an array-mutation operation on a VStore participating in a deferred array copy relationship is commonly referred to as the copy-on-write requirement. When an array-mutating operation is about to be performed on a given VStore X with an “Arr” type tag that participates in a deferred array copy relationship, the engine must find all of the VStores tagged “Arr-D” that point to the same array HStore that VStore X points to, make a copy of the array (using member-copy assignment to copy the array’s elements as described in [§§](#value-assignment-of-array-types-to-local-variables)), and update all of these VStores tagged “Arr-D” to point to the newly created copy (note that VStore X remains unchanged). When an array-mutation operation is about to be performed on a given VStore X with an “Arr-D” type tag, the engine must make a copy of the array (as described in [§§](#value-assignment-of-array-types-to-local-variables)), update VStore X to point to the newly created copy, and change VStore X’s type tag to “Arr”. These specific actions that the engine must perform on VStore at certain times to satisfy the copy-on-write requirement are collectively referred to as “array-separation” or “array-separating the VStore”. An array-mutation operation is said to “trigger” an array-separation. Note that for any VStore with an “Arr” type tag that participates in a deferred array copy relationship, or for any VStore with an “Arr-D” type tag, a conforming implementation may choose to array-separate the VStore at any time for any reason as long as the copy-on-write requirement is upheld. Continuing with the previous example, consider the array-mutating operation `$b[1]++`. Depending on the implementation, this can produce one of three possible outcomes. Here is the one of the possible outcomes:
[VSlot $a *]---->[VStore Arr *]---->[HStore Array [VSlot 0 *]] | [VSlot $b *]-->[VStore Arr *] [VStore Arr *]<---+ | | +----------------------+ +--------+ V V [HStore Array [VSlot 0 *] [VSlot 1 *]] [HStore Array [VSlot 0 *] [VSlot 1 *]] | | ^ | | | V | V | | [VStore Int 1] | [VStore Int 123] | V | ^ V [VStore Arr-D *]-----+ | [VStore Str 'hi'] | [VSlot $x *]----------------------------------------------+As we can see in the outcome shown above, `$b`’s VStore was array-separated and now `$a`’s VStore and `$b`’s VStore point to distinct array HStores. Performing array-separation on `$b`’s VStore was necessary to satisfy the copy-on-write requirement. `$a`’s array remains unchanged and that `$x` and `$a[0][0]` still have an alias relationship with each other. For this particular example, conforming implementations are required to preserve `$a`’s array’s contents and to preserve the alias relationship between `$x` and `$a[0][0]`. Finally, note that `$a[0]` and `$b[0]` have a deferred copy relationship with each other in the outcome shown above. For this particular example, a conforming implementation is not required to array-separate `$b[0]`’s VStore, and the outcome shown above demonstrates what happens when `$b[0]`’s VStore is not array-separated. However, an implementation can choose to array-separate `$b[0]`’s VStore at any time if desired. The other two possible outcomes shown below demonstrate what can possibly happen if the implementation choose to array-separate `$b[0]`’s VStore as well. Here is the second possible outcome:
[VSlot $a *]---->[VStore Arr *]---->[HStore Array [VSlot 0 *]] | [VSlot $b *]-->[VStore Arr *] [VStore Arr *]<---+ | | V V [HStore Array [VSlot 0 *] [VSlot 1 *]] [HStore Array [VSlot 0 *] [VSlot 1 *]] | | | | +-----------------+ V | | | [VStore Int 1] +---+ | V | V [VStore Arr-D *]-->[HStore Array [VSlot 0 *] [VSlot 1 *]] | [VStore Str 'hi'] | | | +-------+ | | | V | | [VStore Str ‘hi’] | V | [VSlot $x *]--------------------->[VStore Int 123]<--------+Here is the third possible outcome:
[VSlot $a *]---->[VStore Arr *-]---->[HStore Array [VSlot 0 *]] | [VSlot $b *]-->[VStore Arr *] [VStore Arr *]<---+ | | V V [HStore Array [VSlot 0 *] [VSlot 1 *]] [HStore Array [VSlot 0 *] [VSlot 1 *]] | | | | +-----------------+ V | | | [VStore Int 1] +---+ | V | V [VStore Arr-D *]-->[HStore Array [VSlot 0 *] [VSlot 1 *]] | [VStore Str 'hi'] | | | [VStore Int 123]<-------+ | | V | [VStore Str 'hi'] | | [VSlot $x *]--------------------->[VStore Int 123]<--------+The second and third possible outcomes show what can possibly happen if the implementation chooses to array-separate `$b[0]`’s VStore. In the second outcome, `$b[0][0]` has an alias relationship with `$x` and `$a[0][0]`. In the third outcome, `$b[0][0]` does not have an alias relationship, though `$x` and `$a[0][0]` still have an alias relationship with each other. The differences between the second and third outcome are reflect that different possibilities when the engine uses member-copy assignment to copy `$a[0]`’s arrays’s elements into `$b[0]`’s array. Finally, let’s briefly consider one more example: ```Hack $x = 0; $a = array(&$x); $b = $a; $x = 2; unset($x); $b[1]++; $b[0]++; echo $a[0], ' ', $b[0]; ``` For the example above, a conforming implementation could output “2 1”, “2 3”, or “3 3” depending on how it implements value assignment for arrays. For portability, it is generally recommended that programs written in Hack should avoid performing value assignment with a right-hand side that is an array with one or more elements or sub-elements that have an alias relationship. ***Implementation Notes*** For generality and for simplicity, the abstract model represents deferred array copy mechanisms in a manner that is more open-ended and superficially different than the php.net implementation’s model, which uses a symmetric deferred copy mechanism where a single zval contains the sole pointer to a given Hashtable and deferred array copies are represented as multiple slots pointing to the same single zval that holds the array. Despite this superficial difference, php.net’s implementation produces behavior that is compatible with the abstract model’s definition of deferred array copy mechanisms. #### General Value Assignment The sections above thus far have described the mechanics of value assignment to a local variable. This section describes how value assignment works when general modifiable lvalue expressions are used on the left hand side. For example, assuming `Point` definition as in previous sections and further assuming all instance properties are public, this code: ```Hack $a = new Point(1, 3); $b = 123; $a->x = $b; ``` will result in:
[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *]]
| |
V V
[VStore int 123] [VStore int 3]
[VSlot $b *]-->[VStore int 123]
If needed, new VSlots are created as part of the containing VStore, for example:
```Hack
$a = new Point(1, 3);
$b = 123;
$a->z = $b;
```
will result in:
[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *] [VSlot $z *]]
| | |
V V V
[VStore int 1] [VStore int 3] [VStore int 123]
[VSlot $b *]-->[VStore int 123]
The same holds for array elements:
```Hack
$a = array('hello', 'world');
$b = 'hack';
$a[1] = $b;
$a[2] = 'World!';
```
will result in:
[VSlot $a *]-->[VStore array *]-->[HStore Array [VSlot 0 *] [VSlot 1 *] [VSlot 2 *]]
| | |
V V V
[VStore string 'hello'] [VStore string 'hack'] [VStore string 'World!']
[VSlot $b *]-->[VStore string 'hack']
where the third VSlot with index 2 was created by the assignment.
Note that any array element and instance property, including a designation of non-existing ones,
is considered a modifiable lvalue, and the VSlot will be created by the engine and added
to the appropriate HStore automatically. Static class properties are considered modifiable lvalues too,
though new ones would not be created automatically.
#### General ByRef Assignment
The sections above thus far have described the mechanics of byref assignment
with local variables. This section describes how byref assignment works when
general modifiable lvalue expressions are used on the left hand side and/or
the right hand side.
For example:
```Hack
$a = new Point(1, 3);
$b = 123;
$a->z =& $b;
```
will result in:
[VSlot $a *]-->[VStore object *]-->[HStore Point [VSlot $x *] [VSlot $y *] [VSlot $z *]]
| | |
V V |
[VStore int 1] [VStore int 3] |
[VSlot $b *]---------------->[VStore int 123]<---------------------------------------+
### Argument Passing
Argument passing is defined in terms of simple assignment[§§](#value-assignment-of-scalar-types-to-a-local-variable), [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable), [§§](#value-assignment-of-array-types-to-local-variables), and [§§](10-expressions.md#simple-assignment)).
That is, passing an argument to a function having a corresponding
parameter is like assigning that argument to that parameter.
### Value Returning
Returning a value from a function is defined in terms of simple
assignment ([§§](#value-assignment-of-scalar-types-to-a-local-variable), [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable), [§§](#value-assignment-of-array-types-to-local-variables), and [§§](10-expressions.md#simple-assignment)). That is, returning a value from a function to its
caller is like assigning that value to the user of the caller's return
value.
### Cloning objects
When an instance is allocated, [operator `new`](10-expressions.md#the-new-operator) returns a handle
that points to that object. (As described in [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable)), value assignment of a handle to an object does not copy the object HStore itself. Instead, it creates a copy of the handle. How then to make a copy of the object itself? Our only access to it is
via the handle. The Hack language allows us to do this via [operator `clone`](10-expressions.md#the-clone-operator).
To demonstrate how the `clone` operator works, consider the case in which
an instance of class `Widget` contains two instance properties: `$p1` has
the integer value 10, and `$p2` is a handle to an array of elements of
some type(s) or to an instance of some other type.
[VSlot $a *]-->[VStore Obj *]-->[HStore Widget [VSlot $p1 *][VSlot $p2 *]]
| |
V V
[VStore Int 10] [VStore Obj *]
|
V
[HStore ...]
Let us consider the result of `$b = clone $a`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Widget [VSlot $p1 *][VSlot $p2 *]] | | [VSlot $b *]-->[VStore Obj *] V V | [VStore Int 10] [VStore Obj *] +-----------------------+ | V V [HStore Widget [VSlot $p1 *] [VSlot $p2 *]] +--->[HStore ...] | | | V V | [VStore Int 10] [VStore Obj *]-------------+The clone operator will create another object HStore of the same class as the original, copy `$a`’s object’s instance properties using member-copy [assignment `=*`](#value-assignment-of-array-types-to-local-variables). For the example shown above, the handle to the newly created HStore stored into `$b` using value assignment. Note that the clone operator will not recursively clone objects held in `$a`’s instance properties; hence the object copying performed by the clone operator is often referred to as a *shallow copy*. If a *deep copy* of an object is desired, the programmer must achieve this manually by using the method [`__clone`](16-classes.md#method-__clone) or by other means. ## Scope The same name can designate different things at different places in a program. For each different thing that a name designates, that name is visible only within a part of the program called that name's *scope*. The following distinct scopes exist: - Script, which means from the point of declaration/first initialization through to the end of that script, including any [included scripts](12-script-inclusion.md#script-inclusion-operators). - Function, which means from the point of declaration/first initialization through to the end of that [function](15-functions.md#function-definitions). - Class, which means the body of that class and any classes derived from it ([§§](16-classes.md#class-declarations)). - Interface, which means the body of that interface, any interfaces derived from it, and any classes that implement it ([§§](17-interfaces.md#interface-declarations)). - Namespace, which means from the point of declaration/first initialization through to the end of that [namespace](20-namespaces.md#general). A variable declared or first initialized inside a function has function scope. Each function has its own function scope. An [anonymous function](15-functions.md#anonymous-functions) has its own scope separate from that of any function inside which that anonymous function is defined. The scope of a parameter is the body of the function in which the parameter is declared. For the purposes of scope, a [catch-block](11-statements.md#the-try-statement) is treated like a function body, in which case, the *variable-name* in *parameter-declaration-list* is treated like a parameter. The scope of a class member `m` ([§§](16-classes.md#class-members)) declared in, or inherited by, a class type `C` is the body of `C`. The scope of an interface member `m` ([§§](17-interfaces.md#interface-members)) declared in, or inherited by, an interface type `I` is the body of `I`. When a [trait](18-traits.md#general) is used by a class or an interface, the [trait's members](16-classes.md#class-members) take on the scope of a member of that class or interface. ## Storage Duration The lifetime of a variable is the time during program execution that storage for that variable is guaranteed to exist. This lifetime is referred to as the variable's *storage duration*, of which there are three kinds: automatic, static, and allocated. A variable having *automatic storage duration* comes into being and is initialized at its declaration or on its first use, if it has no declaration. Its lifetime is delimited by an enclosing [scope](#scope). The automatic variable's lifetime ends at the end of that scope. Automatic variables lend themselves to being stored on a stack where they can help support argument passing and recursion. [Local variables](07-variables.md#local-variables), which include [function parameters](15-functions.md#function-definitions), have automatic storage duration. A variable having *static storage duration* comes into being and is initialized before its first use, and lives until program shutdown. The following kinds of variables have static storage duration: [function statics](07-variables.md#function-statics), [static properties](07-variables.md#static-properties), and [class and interface constants](07-variables.md#class-and-interface-constants). A variable having *allocated storage duration* comes into being based on program logic by use of the [`new` operator](10-expressions.md#the-new-operator). Ordinarily, once such storage is no longer needed, it is reclaimed automatically by the Engine via its garbage-collection process and the use of [destructors](16-classes.md#destructors). The following kinds of variables have allocated storage duration: [array elements](07-variables.md#array-elements) and [instance properties](07-variables.md#instance-properties). The following example demonstrates the three storage durations: ```Hack class Point { ... } function doit($p1) { $av2 = ...; // auto variable $av2 created and initialized static $sv2 = ...; // static variable $sv2 created and initialized if ($p1) { $av3 = ...; // auto variable $av3 created and initialized static $sv3 = ...; // static variable $sv3 created and initialized ... } global $av1; $av1 = new Point(2, 3); // Point(0,1) is eligible for destruction ... } // $av2 and $av3 are eligible for destruction function main($p1): void { $av1 = new Point(); // auto variable $av1 created and initialized static $sv1 = ...; // static variable $sv1 created and initialized doit(true); } // At end of script, $sv1, $sv2, and $sv3 are eligible for destruction ``` The comments indicate the beginning and end of lifetimes for each variable. If function `doit` is called multiple times, each time it is called, its automatic variables are created and initialized, whereas its static variables retain their values from previous calls. Consider the following recursive function: ```Hack function factorial(int $i): int { if ($i > 1) return $i * factorial($i - 1); else if ($i == 1) return $i; else return 0; } ``` When `factorial` is first called, the local variable parameter `$i` is created and initialized with the value of the argument in the call. Then, if this function calls itself, the same process is repeated each call. Specifically, each time `factorial` calls itself, a new local variable parameter `$i` is created and initialized with the value of the argument in the call. The lifetime of any [VStore](#general) or [HStore](#general) can be extended by the Engine as long as needed. Conceptually, the lifetime of a VStore ends when it is no longer pointed to by any [VSlots](#general). Conceptually, the lifetime of an HStore ends when no VStores have a handle to it. ================================================ FILE: spec/05-types.md ================================================ # Types ## General The meaning of a value is decided by its *type*. Hack's types are categorized as *scalar types* and *composite types*. The scalar types are [Boolean](#the-boolean-type), [integer](#the-integer-type), [floating-point](#the-floating-point-type), [numeric](05-types.md#the-numeric-type), [string](#the-string-type), [array key](05-types.md#the-array-key-type), [null](#the-null-type), and [enumerated](05-types.md#enumerated-types). The non-scalar types are [array](05-types.md#array-types), [class](05-types.md#class-types), [interface](05-types.md#interface-types), [tuple](05-types.md#tuple-types), [shape](05-types.md#shape-types), [closure](05-types.md#closure-types), [resource](05-types.md#resource-types), and [nullable](05-types.md#nullable-types). The [void type](05-types.md#the-void-type) is neither scalar nor non-scalar. The integer, floating-point, and numeric types are known collectively as arithmetic types. (Note carefully, that the library function [is_numeric](http://www.php.net/is_numeric) indicates if a given value is an int, a float, or a [numeric string](05-types.md#the-string-type).) The scalar types are *value types*. That is, a variable of scalar type behaves as though it contains its own value. On the other hand, the non-scalar types are *handles*. A variable of non-scalar type contains information—in a *handle*—that leads to the value. The differences between value types and handles become apparent when it comes to understanding the semantics of assignment, and passing arguments to, and returning values from, functions ([§§](04-basic-concepts.md#the-memory-model)). That said, array types really are a hybrid; on the one hand, an array may contain an arbitrary number of elements separate from the array variable itself, yet on the other hand, certain array operations do have value semantics. **Note**: One could differentiate value types and handles in the same way that pass-by-value and pass-by-reference types are distinguished. Variables are not declared to have a particular type. Instead, a variable's type is decided at runtime by the context in which it is used. A *type constraint* indicates a requirement that a type must fulfill in order to be accepted in a given context. Type constraints are used in [type aliasing](05-types.md#type-aliases), [enum declarations](13-enums.md#enum-declarations), [type parameters](14-generic-types-methods-and-functions.md#type-parameters), and [type constants](16-classes.md#type-constants). The library function [`is_scalar`](http://www.php.net/is_scalar) indicates if a given value has a scalar type. However, that function does not consider `null` to be scalar. To test for `null`, use [`is_null`](http://www.php.net/is_null). Useful library functions for interrogating and using type information include [`gettype`](http://www.php.net/gettype), [`is_type`](http://www.php.net/is_type), [`settype`](http://www.php.net/settype), and [`var_dump`](http://www.php.net/var_dump). **Syntax**
type-specifier: arraykey bool float int num resource string this void alias-type-specifier class-interface-trait-specifier classname-type-specifier closure-type-specifier enum-specifier generic-type-parameter-name map-like-array-type-specifier nullable-type-specifier shape-specifier tuple-type-specifier type-constant-type-name vector-like-array-type-specifier alias-type-specifier: qualified-name enum-specifier: qualified-name class-interface-trait-specifier: qualified-name generic-type-argument-listopt type-specifier-list: type-specifiers ,opt type-specifiers type-specifier type-specifiers , type-specifier type-constraint: as type-specifier type-constant-type-name: name :: name self :: name this :: name type-constant-type-name :: name**Defined elsewhere** * [*classname-type-specifier*](05-types.md#the-classname-type) * [*closure-type-specifier*](05-types.md#closure-types) * [*generic-type-argument-list*](14-generic-types-methods-and-functions.md#type-arguments) * [*generic-type-parameter-name*](14-generic-types-methods-and-functions.md#type-parameters) * [*map-like-array-type-specifier*](05-types.md#array-types) * [*name*](09-lexical-structure.md#names) * [*nullable-type-specifier*](05-types.md#nullable-types) * [*qualified-name*](20-namespaces.md#defining-namespaces) * [*shape-type-specifier*](05-types.md#shape-types) * [*tuple-type-specifier*](05-types.md#tuple-types) * [*vector-like-array-type-specifier*](05-types.md#array-types) **Constraints** The *qualified-name* in *alias-type-specifier* must qualify the *name* of a type alias declared in an [*alias-declaration*](05-types.md#type-aliases). The *qualified-name* in *enum-specifier* must qualify the *name* of an enumerated type declared in an [*enum-declaration*](13-enums.md#enum-declarations). The *qualified-name* in *class-interface-trait-specifier* must qualify the *name* of a class type declared in a [*class-declaration*](16-classes.md#class-declarations), of an interface type declared in an [*interface-declaration*](17-interfaces.md#interface-declarations), or of a trait type declared in a [*trait-declaration*](18-traits.md#trait-declarations). The *name* of a trait type declared in a *trait-declaration* can only be used as a type-specifier in the context of a [*trait-use-clauses*](18-traits.md#trait-declarations). For *name* `::` *name*, the left-hand *name* must be the name of a class or interface that directly or indirectly has a [type-constant member](16-classes.md#type-constants) whose name is the right-hand *name*. For `self` `::` *name*, *name* must be the name of a type-constant member in the current class (including any implemented interfaces). For `this` `::` *name*, *name* must be the name of a type-constant member in the current class/interface hierarchy. A *type-constant-type-name* beginning with `self` or `this` must be used in the context of a class or interface to which `self` or `this`, respectively, can apply. **Semantics** A *type-constant-type-name* specifies a type, as follows: * For *name* `::` *name*, the type is that designated by the type-constant having the right-hand *name*, in the class or interface having the left-hand *name*. * For `self` `::` *name*, used within a class, the type is that designated by the type-constant named *name*, in the enclosing class, ignoring any overrides. * For `this` `::` *name*, used within a class, the type is that designated by the type-constant named *name*, in the enclosing class’s hierarchy resolved in a late-bound context. For a non-static member, this designates the class of the `$this` object; for a static member, this designates the current class. `this` is recommended when accessing abstract type constant names. * In cases of *type-constant-type-name* having the form `x::y::z`, the type is resolved left-to-right. A given type constant can be referenced via multiple names; for example: ```Hack interface I { const type T = int; } class C1 implements I {} class C2 extends C1 {} ``` Here, `I::T`, `C1::T`, and `C2::T`, all refer to the same type constant. Consider the following: ```Hack interface I { const type this = int; // this is a name, NOT a keyword } class C { const type self = I; // self is a name, NOT a keyword } function test10(C::self::this $x): void {} ``` For some examples, see [§§](16-classes.md#type-constants). ## The Boolean Type The Boolean type is `bool`. This type is capable of storing two distinct values, which correspond to the Boolean values `true` and `false`, respectively. The representation of this type and its values is unspecified. The library function [`is_bool`](http://www.php.net/is_bool) indicates if a given value has type `bool`. ## The Integer Type There is one integer type, `int`. This type is binary, signed, and uses twos-complement representation for negative values. The range of values that can be stored is implementation-defined; however, the range [-9223372036854775808, 9223372036854775807], must be supported. Certain operations on integer values produce a mathematical result that cannot be represented as an integer. Examples include the following: - Incrementing the largest value or decrementing the smallest value - Applying the unary minus to the smallest value - Multiplying, adding, or subtracting two values In such cases, the resulting type and value is implementation-defined, but must be one of the following: - The result type is int and the value reflects wrap-around (for example adding 1 to the largest value results in the smallest value) - The computation is done as though the type had some unspecified, arithmetic-like object type with the result being mathematically correct The constants [`PHP_INT_SIZE`, `PHP_INT_MIN` and `PHP_INT_MAX`](06-constants.md#core-predefined-constants) define certain characteristics about type `int`. The library function [`is_int`](http://www.php.net/is_int) indicates if a given value has type int. ## The Floating-Point Type There is one floating-point type, `float`. The `float` type must support at least the range and precision of IEEE 754 64-bit double-precision representation. The library function [`is_float`](http://www.php.net/is_float) indicates if a given value has type `float`. The library function [`is_finite`](http://www.php.net/is_finite) indicates if a given floating-point value is finite. The library function [`is_infinite`](http://www.php.net/is_infinite) indicates if a given floating-point value is infinite. The library function [`is_nan`](http://www.php.net/is_nan) indicates if a given floating-point value is a `NaN`. ## The Numeric Type The type `num` can represent any integer or floating-point value. See the discussion of [type side effects](05-types.md#type-side-effects). ## The String Type There is one string type, `string`. A string is a set of contiguous bytes that represents a sequence of zero or more characters. Conceptually, a string can be considered as an [array](05-types.md#array-types) of bytes—the *elements*—whose keys are the `int` values starting at zero. The type of each element is `string`. However, a string is *not* considered a collection, so it cannot be iterated over. A string whose length is zero is an *empty string*. As to how the bytes in a string translate into characters is unspecified. Although a user of a string might choose to ascribe special semantics to bytes having the value `U+0000`, from Hack's perspective, such *null bytes* are simply just bytes! Hack does not assume strings contain any specific data or assign special values to any bytes or sequences. However, many library functions assume the strings they receive as arguments are UTF-8 encoded, often without explicitly mentioning that fact. A *numeric string* is a string whose content exactly matches the pattern defined by the *str-numeric* production below. A *leading-numeric string* is a string whose initial characters follow the requirements of a numeric string, and whose trailing characters are non-numeric. A *non-numeric string* is a string that is not a numeric string.
str-numeric::
str-whitespaceopt signopt str-number
str-whitespace::
str-whitespaceopt str-whitespace-char
str-whitespace-char::
new-line
Space character (U+0020)
Horizontal-tab character (U+0009)
Vertical-tab character (U+000B)
Form-feed character (U+000C)
str-number::
digit-sequence
floating-literal
**Defined elsewhere**
* [*digit-sequence*](09-lexical-structure.md#floating-point-literals)
* [*floating-literal*](09-lexical-structure.md#floating-point-literals)
* [*new-line*](09-lexical-structure.md#comments)
* [*sign*](09-lexical-structure.md#floating-point-literals)
Note that *digit-sequence* is interpreted as having base-10 (so `"0377"` is treated as 377 decimal with a redundant
leading zero, rather than as octal 377).
Only one mutation operation may be performed on a string, offset
assignment, which involves the [simple assignment operator `=`](10-expressions.md#simple-assignment).
The library function [`is_string`](http://www.php.net/is_string) indicates if a given value has
type `string`.
## The Array Key Type
The type `arraykey` can represent any integer or string value.
See the discussion of [type side effects](05-types.md#type-side-effects).
## The Null Type
The null type has only one possible value, [`null`](06-constants.md#core-predefined-constants). The representation
of this type and its value is unspecified.
The library function [`is_null`](http://www.php.net/is_null) indicates if a given value is `null`.
## Enumerated Types
Enumerated types are described in [§§](13-enums.md#enums).
## The Void Type
The type `void` indicates the absence of a value. Its primary use is as the
return type of a function.
## Array Types
**Syntax**
vector-like-array-type-specifier: array < array-value-type-specifier > map-like-array-type-specifier: array < array-value-type-specifier , array-value-type-specifier > array-value-type-specifier: type-specifier array-key-type-specifier: type-specifier**Defined elsewhere** * [*type-specifier*](05-types.md#general). **Constraints** This is not currently a syntax constraint, but ... Although *array-key-type-specifier* can really be any type, behind the scenes, the key is actually represented as an `int` or `string`, so (possibly surprising, or at least, unexpected) conversions occur when other key types are specified. Similarly, *array-value-type-specifier* can really be any type. Programmers are strongly advised to avoid using key types other than `int` or `string`. **Semantics** An *array* is a data structure that contains a collection of zero or more elements each of which is accessed through a corresponding key. As the number of elements in an array can change at runtime, the *type-specifier* for an array does not include an element count. For a *vector-like-array-type-specifier*, the array has an implicit key type of `int`, and an explicit value type as indicated by *array-value-type-specifier*. For a *map-like-array-type-specifier*, the array has an explicit key type as indicated by *array-key-type-specifier*, and an explicit value type as indicated by *array-value-type-specifier*. Each element in an array must have a type that is the exact type indicated by *array-value-type-specifier*, or a [subtype](05-types.md#supertypes-and-subtypes) of that type. For example, an array of `num` can contain a mixture of `int` elements and `float` elements. An array element can have any type (which allows for arrays of arrays). An array is represented as an ordered map in which each entry is a key/value pair that represents an element. Duplicate keys are not permitted. The order of the elements in the map is the order in which the elements were inserted into the array. An element is said to *exist* once it has been inserted into the array with a corresponding key. An array is *extended* by initializing a previously non-existent element using a new key. Elements cannot be removed from an array. The [`foreach` statement](11-statements.md#the-foreach-statement) can be used to iterate over the collection of elements in an array, in the order in which the elements were inserted. This statement provides a way to access the key and value for each element. Each array has its own current element pointer that designates the current array element. When an array is created, the current element is the first element inserted into the array. [Note: Arrays in Hack are quite different to arrays in numerous mainstream languages. Specifically, in Hack, array elements need not have the same type, the subscript index need not be an integer (so there is no concept of a base index of zero or 1), and there is no concept of consecutive elements occupying physically adjacent memory locations.] An array is created and initialized by one of two equivalent ways: via the [array-creation operator `[]`](10-expressions.md#array-creation-operator) or the intrinsic [`array`](10-expressions.md#array). The value (and possibly the type) of an existing element is obtained or changed, and new elements are inserted, using the [subscript operator `[]`](10-expressions.md#subscript-operator). The library function [`is_array`](http://www.php.net/is_array) indicates if a given value is an array. Numerous other library functions are available to create and/or manipulate arrays. **Examples** ```Hack private array
tuple-type-specifier: ( type-specifier , type-specifier-list )**Defined elsewhere** * [*type-specifier*](05-types.md#general) * [*type-specifier-list*](05-types.md#general) **Semantics** A *tuple* is a sequence of one or more elements the number of which is fixed at the time of tuple creation. After a tuple has been created, no elements can be added or removed, and the type of an existing element cannot be changed. However, the value of any existing element can be changed. Each element can have any type, and each unique, lexically ordered combination of element types designates a distinct tuple type. A tuple can be indexed with the [subscript operator](10-expressions.md#subscript-operator). The index of the first element is zero, with subsequent elements having index values one more than their predecessor. Specifically, for a tuple having n elements, their indices are 0–*n*-1. Note: Although a tuple of only one element can be created using a [tuple literal](10-expressions.md#tuple-literals), a *tuple-type-specifier* must contain at least two elements. While this disallows a function to take an argument or to return a value of type (*T*), for example, one could simply declare that function to take or return a value of type *T* directly instead. **Examples** ```Hack function f1((int, string) $p): void { … } // ----------------------------------------- function f2(): (bool, array
shape-specifier: shape ( field-specifier-listopt ) field-specifier-list: field-specifier field-specifier-list , field-specifier field-specifier: single-quoted-string-literal => type-specifier qualified-name => type-specifier scope-resolution-expression => type-specifier**Defined elsewhere** * [*qualified-name*](20-namespaces.md#defining-namespaces) * [*scope-resolution-expression*](10-expressions.md#scope-resolution-operator) * [*single-quoted-string-literal*](09-lexical-structure.md#single-quoted-string-literals) * [*type-specifier*](05-types.md#general) **Constraints** The *qualified-name* or *scope-resolution-expression* must designate a [class constant](16-classes.md#constants) of type `int` or `string`. Each string in the set of strings designated by all the *single-quoted-string-literals*, *qualified-names* and *scope-resolution-expressions* in a *field-specifier-list* must have a distinct value. Each integer in the set of all the *qualified-names* and *scope-resolution-expressions* in a *field-specifier-list* must have a distinct value. The *field-specifiers* in a *field-specifier-list* must all have the *single-quoted-string-literal* form, or all have the *qualified-name* or *scope-resolution-expression* form; the forms must not be mixed. **Semantics** A *shape* consists of a group of zero or more data *fields* taken together as a whole. [It takes on the role of what C and C# call a struct.] Such a construct is sometimes referred to as a "lightweight class". A *shape-specifier* defines a shape type as having an unordered set of fields each of which has a name (indicated by *single-quoted-string-literal*, *qualified-name* or *scope-resolution-operator*) and a type (indicated by *type-specifier*). A field in a shape is accessed using its name as the key in a [*subscript-expression*](10-expressions.md#subscript-operator) that operates on a shape of the corresponding shape type. A field that has a [nullable type](05-types.md#nullable-types) need not be mentioned in any initializer of, or assignment to, a variable of that type; however, until its value is set explicitly, that field does not actually exist in the shape. Consider the following: ```Hack function f3(shape('a' => int, 'n' => ?string) $p): void { echo "\$p['a']: " . $p['a'] . "\n"; echo "\$p['n']: " . $p['n'] . "\n"; // only permitted if n exists } ``` Given the call `f3(shape('a' => 10, 'n' => null))`, field `n` has its value set explicitly, and `f3` works fine. However, given the call `f3(shape('a' => 10))`, field `n` does not have its value set explicitly, in which case, attempting to access that field using `$p['n']` results in an “undefined index” error at runtime. To be certain such accesses succeed, first call [`Shapes::keyExists`](16-classes.md#class-shapes). Consider a shape type *S2* whose field set is a superset of that in shape type *S1*. As such, *S2* is a subtype of *S1*. (See the banking example below.) However, when an *S2* is used as an *S1*, only the *S1* fields in that *S2* are accessible. **Examples** ```Hack shape('x' => int, 'y' => int) shape('real' => float, 'imag' => float) shape('id' => string, 'url' => string, 'count' => int) shape('name' => string, 'address' => shape('street' => string, 'city' => string, 'state' => string, 'postcode' => int)); type APoint
closure-type-specifier: ( function ( type-specifier-listopt ) : type-specifier )**Defined elsewhere** * [*type-specifier*](05-types.md#general) * [*type-specifier-list*](05-types.md#general) **Semantics** A *closure* is an object that encapsulates a function with a given argument list and return type. The function can then be called through that object by using the [function-call operator](10-expressions.md#function-call-operator). Note: The library functions [`class_meth`](http://www.php.net/class_meth), [`fun1](http://www.php.net/fun), [`inst_meth`](http://www.php.net/inst_meth), and [`meth_caller`](http://www.php.net/meth_caller) allow a string constant containing the name of a function to be turned into a closure. **Examples** ```Hack private (function (): void) $prop; public function setProcess1((function (int): (int, int)) $val): void { … } public function getProcess2(): (function (): ?array
nullable-type-specifier: ? type-specifier mixed**Defined elsewhere** * [*type-specifier*](05-types.md#general) **Constraints** *type-specifier* must not be `void` or `mixed`. **Semantics** Except for the type `mixed`, a *nullable* type can represent all of the values of its underlying type, plus an additional value, `null`. In such cases, a nullable type is written *?T*, where *T* is the underlying type. For example, a variable of type `?bool` can contain the values `true`, `false`, or `null`. A variable of type `mixed` can represent the values of any other type, including any nullable type, which makes mixed a nullable type. (As such, there is no type `?mixed`.) See the discussion of [type side effects](05-types.md#type-side-effects). **Examples** ```Hack private ?bool $pr_nbool; private mixed $pr_mixed; private array $a_nint = array(3, null); // array of nullable int private ?Button $pr_nButton; // nullable class private ?MyCollection $pr_nMyCollection; // nullable interface private ?(int, ?string, ?(bool, int)) $pr; // nullable tuple whose // second element has type "nullable string", and whose third element // has type "nullable tuple of bool and int" ``` ## Generic Types Hack contains a mechanism to define generic (that is, type-less) classes, interfaces, and traits, and to create type-specific instances of them via parameters. See [§§](14-generic-types-methods-and-functions.md#generic-types-methods-and-functions). ## The Classname Type **Syntax**
classname-type-specifier: classname < qualified-name generic-type-argument-listopt >**Defined elsewhere** * [*qualified-name*](20-namespaces.md#defining-namespaces) **Constraints** *qualified-name* must be the name of a class or interface type. **Semantics** This type gets around some limitations Hack has that its ancestor, PHP, does not. Specifically, the use of type-name strings as operands to [`new`](10-expressions.md#the-new-operator), [`instanceof`](10-expressions.md#instanceof-operator), and [`::`](10-expressions.md#scope-resolution-operator), is prohibited in Hack. However, equivalent functionality is possible via an instance of this type (which can only be created via `::`). The value of an expression of the classname type can be converted implicitly or explicitly to type [`string`](08-conversions.md#converting-to-string-type). The classname type is not assignment-compatible with any other type. The representation of a value having the classname type is unspecified. **Examples** ```Hack namespace NS_cn; class C1 { … } class C2 { public static classname<\NS_cn\C1> $p1 = \NS_cn\C1::class; public static function f(?classname
alias-declaration: attribute-specificationopt type name generic-type-parameter-listopt = type-specifier ; attribute-specificationopt newtype name generic-type-parameter-listopt type-constraintopt = type-specifier ;**Defined elsewhere** * [*attribute-specification*](21-attributes.md#attribute-specification) * [*generic-type-parameter-list*](14-generic-types-methods-and-functions.md#type-parameters) * [*name*](09-lexical-structure.md#names) * [*type-constraint*](05-types.md#general) * [*type-specifier*](05-types.md#general) **Constraints** The *type-specifier* in the optional *type-constraint* must be a subtype of the *type-specifier* to the right of the equals. **Semantics** An *alias-declaration* creates an alias *name* for the specified type. Once such a type alias has been defined, that alias can be used in any context in which a *type-specifier* is permitted. Any given type can have multiple aliases, and a type alias can itself have aliases. An alias created using `type` is a *transparent type alias*. For a given type, that type and all transparent aliases to that type are all the same type, and can be freely interchanged. There are no restrictions on where a transparent type alias can be defined or which source code can access its underlying implementation. An alias created using `newtype` is an *opaque type alias*. In the absence of a *type-constraint*, each opaque alias type is distinct from its underlying type and from any other types aliasing it or its underlying type. Only source code in the file that contains the definition of the opaque type alias is allowed access to the underlying implementation. As such, opaque type aliasing is an abstraction mechanism. Consider the following file, which contains an opaque alias definition: ```Hack newtype Point = (int, int); function create_point(int $x, int $y): Point { return tuple($x, $y); } function distance(Point $p1, Point $p2): float { $dx = $p1[0] - $p2[0]; $dy = $p1[1] - $p2[1]; return sqrt($dx*$dx + $dy*$dy); } ``` Being in the same file as the alias definition, the functions `create_point` and distance have direct access to the integer fields in any `Point`'s tuple. However, any file that includes this file does not. Similarly, if a file defines the following alias: `newtype Widget = int;` any file that includes this file has no knowledge that a `Widget` is really an integer, so that the including file cannot perform any integer-like operations on a `Widget`. The presence of a *type-constraint* allows an opaque type alias to be treated as if it had the type specified by *type-specifier* in *type-constraint*, which removes some of the alias' opaqueness. Note: Although the presence of a constraint allows the alias type to be converted implicitly to that constraint type, there is no conversion in the opposite direction. **Examples** ```Hack type Counter = int; newtype NameList = array
function-static-declaration:
static static-declarator-list ;
static-declarator-list:
static-declarator
static-declarator-list , static-declarator
static-declarator:
variable-name function-static-initializeropt
function-static-initializer:
= const-expression
**Defined elsewhere**
* [*variable-name*](09-lexical-structure.md#names)
* [*constant-expression*](10-expressions.md#constant-expressions)
**Semantics**
A function static may be defined inside any [compound statement](11-statements.md#compound-statements).
It is a modifiable lvalue.
A function static has [function scope](04-basic-concepts.md#scope) and
[static storage duration](04-basic-concepts.md#storage-duration).
The value of a function static is retained across calls to its parent
function. Each time the function containing a function static
declaration is called, that execution is dealing with an [alias](04-basic-concepts.md#general)
to that static variable. The next time that function
is called, a new alias is created.
**Examples**
```Hack
function f(): void {
static $fs = 1;
echo "\$fs = $fs\n";
++$fs;
}
for ($i = 1; $i <= 3; ++$i)
f();
```
Unlike the [local variable equivalent](07-variables.md#local-variables), function `f` outputs "`$fs
= 1`", "`$fs = 2`", and "`$fs = 3`", as `$fs` retains its value across
calls.
### Instance Properties
These are described in [class instance properties section](16-classes.md#properties). They have [class scope](04-basic-concepts.md#scope) and [allocated storage duration](04-basic-concepts.md#storage-duration).
### Static Properties
These are described in [class static properties section](16-classes.md#properties). They have [class scope](04-basic-concepts.md#scope) and [static storage duration](04-basic-concepts.md#storage-duration).
### Class and Interface Constants
These are described in [class constants section](16-classes.md#constants) and [interface constants section](17-interfaces.md#constants). They have [class or interface scope](04-basic-concepts.md#scope) and [static storage duration](04-basic-concepts.md#storage-duration).
================================================
FILE: spec/08-conversions.md
================================================
# Conversions
## General
Some operators implicitly convert automatically the values of operands
from one type to another. Explicit conversion is performed using the
[cast operator](10-expressions.md#cast-operator).
If an expression is converted to its own type, the type and value of the
result are the same as the type and value of the expression.
When an expression of type `num` is converted, if that expression is currently
an `int`, then `int` conversion rules apply; otherwise, `float` conversion rules apply.
When an expression of type `arraykey` is converted, if that expression is
currently an `int`, then `int` conversion rules apply; otherwise, `string`
conversion rules apply.
## Converting to Boolean Type
No non-`bool` type can be converted implicitly to `bool`. All other conversions
must be explicit.
The [result type](http://docs.hhvm.com/manual/en/language.types.boolean.php#language.types.boolean.casting) is `bool`.
If the source type is `int` or `float`, then if the source value tests equal
to 0, the result value is `false`; otherwise, the result value is `true`.
If the source value is `null`, the result value is `false`.
If the source is an empty string or the string "0", the result value is
`false`; otherwise, the result value is `true`.
If the source is an array with zero elements, the result value is `false`;
otherwise, the result value is `true`.
If the source is an object, the result value is `true`.
If the source is a resource, the result value is `false`.
The library function [`boolval`](http://www.php.net/boolval) allows values to be converted to
`bool`.
## Converting to Integer Type
No non-`int` type can be converted implicitly to `int`. All other conversions must be explicit.
The [result type](http://docs.hhvm.com/manual/en/language.types.integer.php#language.types.integer.casting) is `int`.
If the source type is `bool`, then if the source value is `false`, the
result value is 0; otherwise, the result value is 1.
If the source type is `float`, for the values `INF`, `-INF`, and `NAN`, the
result value is implementation-defined. For all other values, if the
precision can be preserved, the fractional part is rounded towards zero
and the result is well defined; otherwise, the result is undefined.
If the source value is `null`, the result value is 0.
If the source is a [numeric string or leading-numeric string](05-types.md#the-string-type)
having integer format, if the precision can be preserved the result
value is that string's integer value; otherwise, the result is
undefined. If the source is a numeric string or leading-numeric string
having floating-point format, the string's floating-point value is
treated as described above for a conversion from `float`. The trailing
non-numeric characters in leading-numeric strings are ignored. For any
other string, the result value is 0.
If the source is an array with zero elements, the result value is 0;
otherwise, the result value is 1.
If the source is a resource, the result is the resource's unique ID.
The library function [`intval`](http://docs.hhvm.com/manual/en/function.intval.php) allows values
to be converted to `int`.
## Converting to Floating-Point Type
No non-`float` type can be converted implicitly to `float`. All other
conversions must be explicit.
The [result type](http://docs.hhvm.com/manual/en/language.types.float.php#language.types.float.casting) is `float`.
If the source type is `int`, if the precision can be preserved the result
value is the closest approximation to the source value; otherwise, the
result is undefined.
If the source is a [numeric string or leading-numeric string](05-types.md#the-string-type)
having integer format, the string's integer value is treated as
described above for a conversion from `int`. If the source is a numeric
string or leading-numeric string having floating-point format, the
result value is the closest approximation to the string's floating-point
value. The trailing non-numeric characters in leading-numeric strings
are ignored. For any other string, the result value is 0.
If the source is an array with zero elements, the result value is 0.0;
otherwise, the result value is 1.0.
If the source is a resource, the result is the resource's unique ID.
The library function [`floatval`](http://www.php.net/floatval) allows values to be converted to
float.
## Converting to Number Type
The only implicit conversions to type `num` are from the types `int` and
`float`. There is no change in representation during such conversions. There are no explicit conversions.
The result type is `num`.
## Converting to String Type
Except for the [`classname` type](05-types.md#the-classname-type), no non-`string` type can be converted implicitly to `string`. All other conversions must be explicit.
The [result type](http://docs.hhvm.com/manual/en/language.types.string.php#language.types.string.casting) is `string`.
If the source type is `bool`, then if the source value is `false`, the
result value is the empty string; otherwise, the result value is "1".
If the source type is `int` or `float`, then the result value is a string
containing the textual representation of the source value (as specified
by the library function [`sprintf`](http://www.php.net/sprintf).
If the source value is `null`, the result value is an empty string.
If the source is an object, then if that object's class has a
[`__toString` method](16-classes.md#method-__tostring), the result value is the string returned
by that method; otherwise, the conversion is invalid.
If the source is a resource, the result value is an
implementation-defined string.
If the source type is the [`classname` type](05-types.md#the-classname-type), the result value is a string containing the corresponding fully qualified class or interface name without any leading `\`.
The library function [`strval`](http://www.php.net/strval) allows values to be converted to
`string`.
## Converting to Array Key Type
The only implicit conversions to type `arraykey` are from the types `int`
and `string`. There is no change in representation during such conversions.
There are no explicit conversions.
The result type is `arraykey`.
## Converting to Array Type
For arrays of different types, no implicit conversions exist. There are no
explicit conversions.
## Converting to Object Type
An object type can be converted implicitly to any object type from which the first object type is derived directly or indirectly. There are no other implicit or explicit conversions.
## Converting to Interface Type
An object type can be converted implicitly to any interface type that object
type implements directly or indirectly.
An interface type can be converted implicitly to any interface type from which
the first interface type is derived directly or indirectly.
There are no other implicit or explicit conversions.
## Converting to Resource Type
The [predefined resource-like constants](05-types.md#resource-types)) `STDIN`, `STDOUT`, and
`STDERR`, can be converted implicitly to resource. No other non-resource type
can be so converted. No explicit conversions exist.
## Converting to Mixed Type
Any type can be converted implicitly to [`mixed`](05-types.md#nullable-types). No explicit conversions
exist.
================================================
FILE: spec/09-lexical-structure.md
================================================
# Lexical Structure
## Scripts
A [script](04-basic-concepts.md#program-structure) is an ordered sequence of characters. Typically, a
script has a one-to-one correspondence with a file in a file system, but
this correspondence is not required.
Conceptually, a script is translated using the following steps:
1. Transformation, which converts a script from a particular character
repertoire and encoding scheme into a sequence of 8-bit characters.
2. Lexical analysis, which translates a stream of input characters into
a stream of tokens.
3. Syntactic analysis, which translates the stream of tokens into
executable code.
Conforming implementations must accept scripts encoded with the UTF-8
encoding form (as defined by the Unicode standard), and transform them
into a sequence of characters. Implementations can choose to accept and
transform additional character encoding schemes.
## Grammars
This specification shows the syntax of the Hack programming language
using two grammars. The *lexical grammar* defines how source
characters are combined to form white space, comments, and tokens. The
*syntactic grammar* defines how the resulting tokens are combined to
form Hack programs.
The grammars are presented using *grammar productions*, with each one
defining a non-terminal symbol and the possible expansions of that
non-terminal symbol into sequences of non-terminal or terminal symbols.
In productions, non-terminal symbols are shown in slanted type *like
this*, and terminal symbols are shown in a fixed-width font `like this`.
The first line of a grammar production is the name of the non-terminal
symbol being defined, followed by one colon for a syntactic grammar
production, and two colons for a lexical grammar production. Each
successive indented line contains a possible expansion of the
non-terminal given as a sequence of non-terminal or terminal symbols.
For example, the production:
single-line-comment::
// input-charactersopt
# input-charactersopt
defines the lexical grammar production *single-line-comment* as being
the terminals `//` or `#`, followed by an optional *input-characters*. Each
expansion is listed on a separate line.
Although alternatives are usually listed on separate lines, when there
is a large number, the shorthand phrase “one of” may precede a list of
expansions given on a single line. For example,
hexadecimal-digit:: one of
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F
## Grammar ambiguities
In general, lexical processing results in the creation of the longest possible
lexical element. However, in certain cases involving generic type specifiers
(and array specifiers, which use generic type notation), this is not the case.
For example, in type specifiers like `X
input-file::
input-element
input-file input-element
input-element::
comment
white-space
token
**Defined elsewhere**
* [*comment*](09-lexical-structure.md#comments)
* [*token*](09-lexical-structure.md#general-1)
* [*white-space*](09-lexical-structure.md#white-space)
**Semantics:**
The basic elements of a script are comments, white space, and tokens.
The lexical processing of a script involves the reduction of that script
into a sequence of [tokens](09-lexical-structure.md#tokens) that becomes the input to the
syntactic analysis. Tokens can be separated by [white space](09-lexical-structure.md#white-space) and
[delimited comments](09-lexical-structure.md#comments).
Apart from the exception noted in [§§](09-lexical-structure.md#grammar-ambiguities), lexical processing always results in the creation of the longest
possible lexical element. (For example, `$a+++++$b` must be parsed as
`$a++ ++ +$b`, which syntactically is invalid.)
### Comments
Two forms of comments are supported: *delimited comments* and
*single-line comments*.
**Syntax**
comment::
single-line-comment
delimited-comment
single-line-comment::
// input-charactersopt
# input-charactersopt
input-characters::
input-character
input-characters input-character
input-character::
Any source character except new-line
new-line::
Carriage-return character (U+000D)
Line-feed character (U+000A)
Carriage-return character (U+000D) followed by line-feed character (U+000A)
delimited-comment::
/* No characters or any source character sequence except /* */
**Semantics**
Except within a string literal or a comment, the characters /\* start a
delimited comment, which ends with the characters \*/. Except within a
string literal or a comment, the characters // or \# start a single-line
comment, which ends with a new line. That new line is not part of the
comment. However, if the single-line comment is the last source element
in an embedded script, the trailing new line can be omitted. (Note: this
allows for uses like ``.)
A delimited comment can occur in any place in a script in which [white
space](09-lexical-structure.md#white-space) can occur. (For example;
`/*...*/$c/*...*/=/*...*/567/*...*/;/*...*/` is parsed as `$c=567;`, and
`$k = $i+++/*...*/++$j;` is parsed as `$k = $i+++ ++$j;`.)
A number of single-line, so-called special comments are recognized by a
conforming implementation; they are:
* [`// FALLTHROUGH`](11-statements.md#the-switch-statement)
* [`// strict`](04-basic-concepts.md#program-structure)
where horizontal white space is permitted between the `//` and the start of
the comment text.
**Implementation Notes**
During tokenizing, an implementation can treat a delimited comment as
though it was white space.
### White Space
White space consists of an arbitrary combination of one or more
new-line, space, and horizontal tab characters.
**Syntax**
white-space::
white-space-character
white-space white-space-character
white-space-character::
new-line
Space character (U+0020)
Horizontal-tab character (U+0009)
**Defined elsewhere**
* [*new-line*](09-lexical-structure.md#comments)
**Semantics**
The space and horizontal tab characters are considered *horizontal
white-space characters*.
### Tokens
#### General
There are several kinds of source tokens:
**Syntax**
token::
variable-name
name
keyword
literal
operator-or-punctuator
**Defined elsewhere**
* [*keyword*](09-lexical-structure.md#keywords)
* [*literal*](09-lexical-structure.md#general-2)
* [*name*](09-lexical-structure.md#names)
* [*operator-or-punctuator*](09-lexical-structure.md#operators-and-punctuators)
* [*variable-name*](09-lexical-structure.md#names)
#### Names
**Syntax**
variable-name::
$ name
name::
name-nondigit
name name-nondigit
name digit
name-nondigit::
nondigit
one of the characters U+007f–U+00ff
nondigit:: one of
_
a b c d e f g h i j k l m
n o p q r s t u v w x y z
A B C D E F G H I J K L M
N O P Q R S T U V W X Y Z
**Defined elsewhere**
* [*digit*](09-lexical-structure.md#integer-literals)
**Semantics:**
Names are used to identify the following: [constants](06-constants.md#general), [variables](07-variables.md#general), [labels](11-statements.md#labeled-statements), [enumerated types](13-enums.md#enum-declarations), [functions](15-functions.md#function-definitions), [classes](16-classes.md#class-declarations), [class members](16-classes.md#class-members), [interfaces](17-interfaces.md#interface-declarations), [traits](18-traits.md#general), [type aliases](05-types.md#type-aliases), [namespaces](20-namespaces.md#general),
names in [heredoc comments](09-lexical-structure.md#heredoc-string-literals) and [nowdoc comments](09-lexical-structure.md#nowdoc-string-literals); and [attributes](21-attributes.md#attributes).
A *name* begins with an underscore (_), *name-nondigit*, or extended
name character in the range U+007f–U+00ff. Subsequent characters can
also include *digit*s. A *variable name* is a name with a leading
dollar ($).
The name `$_`, referred to as the *placeholder variable*, is reserved for use in the ([`list` intrinsic](§10-expressions.md#list)) and the ([`foreach` statement](§11-statements.md#The-foreach-Statement)). This name does not actually designate any storage; instead, it’s an indication that the value that would otherwise be stored in a variable in that context, is ignored.
Unless stated otherwise ([§§](14-generic-types-methods-and-functions.md#type-parameters), [§§](15-functions.md#function-calls), [§§](16-classes.md#class-declarations), [§§](18-traits.md#trait-members)),
names are case-sensitive, and every character in a name is significant.
Function and method names beginning with two underscores (__) are
reserved by the Hack language.
**Examples**
```Hack
const int MAX_VALUE = 100;
public function getData(): array
keyword:: one of
abstract arraykey as async await break case catch class classname clone const continue default do
echo else elseif enum extends final finally for foreach function if implements
instanceof insteadof interface mixed namespace new newtype noreturn num parent private
protected public require require_once return self shape static switch throw trait try
tuple type use while yield
**Semantics**
Keywords are case-sensitive.
Note: Strictly speaking, `false`, `null`, and `true` are not keywords;
however, they do have predefined meanings, and can be thought of as keywords.
Likewise for the names of the [intrinsics](10-expressions.md#general-2).
#### Literals
##### General
The source code representation of a value is called a *literal*.
**Syntax**
literal::
boolean-literal
integer-literal
floating-literal
string-literal
null-literal
**Defined elsewhere**
* [*boolean-literal*](09-lexical-structure.md#boolean-literals)
* [*floating-literal*](09-lexical-structure.md#floating-point-literals)
* [*integer-literal*](09-lexical-structure.md#integer-literals)
* [*null-literal*](09-lexical-structure.md#the-null-literal)
* [*string-literal*](09-lexical-structure.md#string-literals)
##### Boolean Literals
**Syntax**
boolean-literal::
true
false
**Semantics**
The type of a *boolean-literal* is bool. The values `true` and `false`
represent the Boolean values True and False, respectively.
**Examples**
```Hack
$done = false;
computeValues($table, true);
```
##### Integer Literals
**Syntax**
integer-literal::
decimal-literal
octal-literal
hexadecimal-literal
binary-literal
decimal-literal::
nonzero-digit
decimal-literal digit
octal-literal::
0
octal-literal octal-digit
hexadecimal-literal::
hexadecimal-prefix hexadecimal-digit
hexadecimal-literal hexadecimal-digit
hexadecimal-prefix:: one of
0x 0X
binary-literal::
binary-prefix binary-digit
binary-literal binary-digit
binary-prefix:: one of
0b 0B
digit:: one of
0 1 2 3 4 5 6 7 8 9
nonzero-digit:: one of
1 2 3 4 5 6 7 8 9
octal-digit:: one of
0 1 2 3 4 5 6 7
hexadecimal-digit:: one of
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F
binary-digit:: one of
0 1
**Constraints**
The value of an integer literal must be representable by its type.
**Semantics**
The value of a decimal integer literal is computed using base 10; that
of an octal integer literal, base 8; that of a hexadecimal integer
literal, base 16; and that of a binary integer literal, base 2.
The type of an *integer-literal* is `int`.
Using a twos-complement system, can the smallest negative value
(-9223372036854775808 for 64 bits) be
represented as a decimal integer literal? No. Consider the
expression -5. This is made up of two tokens: a unary minus followed by
the integer literal 5. As such, **there is no such thing as a
negative-valued decimal integer literal in Hack**. Instead, there is the
non-negative value, which is then negated. Literals written using hexadecimal, octal, or binary
notations are considered to have non-negative values.
**Examples**
```Hack
$count = 10 // decimal 10
0b101010 >> 4 // binary 101010 and decimal 4
0XAF << 023 // hexadecimal AF and octal 23
```
##### Floating-Point Literals
**Syntax**
floating-literal::
fractional-literal exponent-partopt
digit-sequence exponent-part
fractional-literal::
digit-sequenceopt . digit-sequence
digit-sequence .
exponent-part::
e signopt digit-sequence
E signopt digit-sequence
sign:: one of
+ -
digit-sequence::
digit
digit-sequence digit
**Defined elsewhere**
* [*digit*](09-lexical-structure.md#integer-literals)
**Constraints**
The value of a floating-point literal must be representable by its type.
**Semantics**
The type of a *floating-literal* is `float`.
The constants [`INF`](06-constants.md#core-predefined-constants) and [`NAN`](06-constants.md#core-predefined-constants) provide access to the floating-
point values for infinity and Not-a-Number, respectively.
**Examples**
```Hack
$values = array(1.23, 3e12, 543.678E-23);
```
##### String Literals
**Syntax**
string-literal::
single-quoted-string-literal
double-quoted-string-literal
heredoc-string-literal
nowdoc-string-literal
**Defined elsewhere**
* [*double-quoted-string-literal*](09-lexical-structure.md#double-quoted-string-literals)
* [*heredoc-string-literal*](09-lexical-structure.md#heredoc-string-literals)
* [*nowdoc-string-literal*](09-lexical-structure.md#nowdoc-string-literals)
* [*single-quoted-string-literal*](09-lexical-structure.md#single-quoted-string-literals)
Note: By conventional standards, calling [*heredoc-string-literal*s](#heredoc-string-literals)
and [*nowdoc-string-literal*s](#nowdoc-string-literals)) literals is a stretch, as
each is hardly a single token. And given the variable substitution permitted in *double-quote-string-literals*, they are not really literals either.
**Semantics**
A string literal is a sequence of zero or more characters delimited in
some fashion. The delimiters are not part of the literal's content.
The type of a string literal is `string`.
###### Single-Quoted String Literals
**Syntax**
single-quoted-string-literal::
' sq-char-sequenceopt '
sq-char-sequence::
sq-char
sq-char-sequence sq-char
sq-char::
sq-escape-sequence
\opt any member of the source character set except single-quote (') or backslash (\)
sq-escape-sequence:: one of
\' \\
**Semantics**
A single-quoted string literal is a string literal delimited by
single-quotes ('). The literal can contain any source character except
single-quote (') and backslash (\\), which can only be represented by
their corresponding escape sequence.
A single-quoted string literal is a [c-constant](06-constants.md#general).
**Examples**
```Hack
'This text is taken verbatim'
'Can embed a single quote (\') and a backslash (\\) like this'
```
###### Double-Quoted String Literals
**Syntax**
double-quoted-string-literal::
" dq-char-sequenceopt "
dq-char-sequence::
dq-char
dq-char-sequence dq-char
dq-char::
dq-escape-sequence
any member of the source character set except double-quote (") or backslash (\)
\ any member of the source character set except "\$efnrtvxX or octal-digit
dq-escape-sequence::
dq-simple-escape-sequence
dq-octal-escape-sequence
dq-hexadecimal-escape-sequence
dq-unicode-escape-sequence
dq-simple-escape-sequence:: one of
\" \\ \$ \e \f \n \r \t \v
dq-octal-escape-sequence::
\ octal-digit
\ octal-digit octal-digit
\ octal-digit octal-digit octal-digit
dq-hexadecimal-escape-sequence::
\x hexadecimal-digit hexadecimal-digitopt
\X hexadecimal-digit hexadecimal-digitopt
dq-unicode-escape-sequence::
\u{ codepoint-digits }
codepoint-digits::
hexadecimal-digit
hexadecimal-digit codepoint-digits
**Defined elsewhere**
* [*hexadecimal-digit*](09-lexical-structure.md#integer-literals)
* [*octal-digit*](09-lexical-structure.md#integer-literals)
**Semantics**
A double-quoted string literal is a string literal delimited by
double-quotes ("). The literal can contain any source character except
double-quote (") and backslash (\\), which can only be represented by
their corresponding escape sequence. Certain other (and sometimes
non-printable) characters can also be expressed as escape sequences.
An escape sequence represents a single-character encoding, as described
in the table below:
Escape sequence | Character name | Unicode character
--------------- | --------------| ------
\$ | Dollar sign | U+0024
\" | Double quote | U+0022
\\ | Backslash | U+005C
\e | Escape | U+001B
\f | Form feed | U+000C
\n | New line | U+000A
\r | Carriage Return | U+000D
\t | Horizontal Tab | U+0009
\v | Vertical Tab | U+000B
\ooo | 1–3-digit octal digit value ooo |
\xhh or \Xhh | 1–2-digit hexadecimal digit value hh | U+00hh
\u{xxxxxx} | UTF-8 encoding of Unicode codepoint U+xxxxxx | U+xxxxxx
Within a double-quoted string literal, except when recognized as the
start of an escape sequence, a backslash (\\) is retained verbatim.
Within a double-quoted string literal a dollar ($) character not
escaped by a backslash (\\) is handled using a variable substitution rules
described below.
The `\u{xxxxxx}` escape sequence produces the UTF-8 encoding of the Unicode
codepoint with the hexadecimal number specified within the curly braces.
Implementations MUST NOT allow Unicode codepoints beyond U+10FFFF as this is
outside the range UTF-8 can encode (see
[RFC 3629](http://tools.ietf.org/html/rfc3629#section-3)). If a codepoint
larger than U+10FFFF is specified, implementations MUST error.
Implementations MUST pass through `\u` verbatim and not interpret it as an
escape sequence if it is not followed by an opening `{`, but if it is,
implementations MUST produce an error if there is no terminating `}` or the
contents are not a valid codepoint. Implementations MUST support leading zeroes,
but MUST NOT support leading or trailing whitespace for the codepoint between
the opening and terminating braces. Implementations MUST allow Unicode
codepoints that are not Unicode scalar values, such as high and low surrogates.
A Unicode escape sequence cannot be created by variable substitution. For example, given `$v = "41"`,
`"\u{$v}"` results in `"\u41"`, a string of length 4, while `"\u{0$v}"` and `"\u{{$v}}"` contain
ill-formed Unicode escape sequences.
**Variable substitution**
The variable substitution accepts the following syntax:
string-variable::
variable-name offset-or-propertyopt
offset-or-property::
offset-in-string
property-in-string
offset-in-string::
[ name ]
[ variable-name ]
[ integer-literal ]
property-in-string::
-> name
**Defined elsewhere**
* [*expression*](10-expressions.md#general-6)
* [*integer-literal*](#integer-literals)
* [*name*](#names)
* [*variable-name*](#names)
After the variable defined by the syntax above is evaluated, its value is converted
to string according to the rules of [string conversion](08-conversions.md#converting-to-string-type)
and is substituted into the string in place of the variable substitution expression.
Subscript or property access defined by *offset-in-string* and *property-in-string*
is resolved according to the rules of the [subscript operator](10-expressions.md#subscript-operator)
and [member selection operator](10-expressions.md#member-selection-operator) respectively.
The exception is that *name* inside *offset-in-string* is interpreted as a string literal even if it is not
quoted.
If the character sequence following the `$` does not parse as *name* then the `$` character
is instead interpreted verbatim and no variable substitution is performed.
A double-quoted string literal is a [c-constant](06-constants.md#general) if it does not
contain any variable substitution.
**Examples**
```Hack
$x = 123;
echo ">\$x.$x"."<"; // → >$x.123<
// -----------------------------------------
$colors = array("red", "white", "blue");
$index = 2;
echo "\$colors[$index] contains >$colors[$index]<\n";
// → $colors[2] contains >blue<
// -----------------------------------------
class C {
public $p1 = 2;
}
$myC = new C();
echo "\$myC->p1 = >$myC->p1<\n"; // → $myC->p1 = >2<
```
###### Heredoc String Literals
**Syntax**
heredoc-string-literal::
<<< hd-start-identifier new-line hd-char-sequenceopt new-line hd-end-identifier ;opt new-line
hd-start-identifier::
name
hd-end-identifier::
name
hd-char-sequence::
hd-char
hd-char-sequence hd-char
hd-char::
hd-escape-sequence
any member of the source character set except backslash (\)
\ any member of the source character set except \$efnrtvxX or
octal-digit
hd-escape-sequence::
hd-simple-escape-sequence
dq-octal-escape-sequence
dq-hexadecimal-escape-sequence
dq-unicode-escape-sequence
hd-simple-escape-sequence:: one of
\\ \$ \e \f \n \r \t \v
**Defined elsewhere**
* [*dq-hexadecimal-escape-sequence*](09-lexical-structure.md#double-quoted-string-literals)
* [*dq-octal-escape-sequence*](09-lexical-structure.md#double-quoted-string-literals)
* [*dq-unicode-escape-sequence*](09-lexical-structure.md#double-quoted-string-literals)
* [*name*](09-lexical-structure.md#names)
* [*new-line*](09-lexical-structure.md#comments)
**Constraints**
The start and end identifier must be the same. Only horizontal white
space is permitted between `<<<` and the start identifier. No white
space is permitted between the start identifier and the new-line that
follows. No white space is permitted between the new-line and the end
identifier that follows. Except for an optional semicolon (`;`), no
characters—not even comments or white space—are permitted between the
end identifier and the new-line that terminates that source line.
**Semantics**
A heredoc string literal is a string literal delimited by
"`<<< name`" and "`name`". The literal can contain any source
character. Certain other (and sometimes non-printable) characters can
also be expressed as escape sequences.
A heredoc literal supports variable substitution as defined for
[double-quoted string literals](09-lexical-structure.md#double-quoted-string-literals).
A heredoc string literal is a [c-constant](06-constants.md#general) if it does not contain
any variable substitution.
**Examples**
```Hack
$v = 123;
$s = <<< ID
S'o'me "\"t e\txt; \$v = $v"
Some more text
ID;
echo ">$s<";
→ >S'o'me "\"t e xt; $v = 123"
Some more text<
```
###### Nowdoc String Literals
**Syntax**
nowdoc-string-literal::
<<< ' hd-start-identifier ' new-line hd-char-sequenceopt new-line hd-end-identifier ;opt new-line
**Defined elsewhere**
* [*hd-char-sequence*](09-lexical-structure.md#heredoc-string-literals)
* [*hd-end-identifier*](09-lexical-structure.md#heredoc-string-literals)
* [*hd-start-identifier*](09-lexical-structure.md#heredoc-string-literals)
* [*new-line*](09-lexical-structure.md#comments)
**Constraints**
No white space is permitted between the start identifier and its
enclosing single quotes ('). See also [§§](09-lexical-structure.md#heredoc-string-literals).
**Semantics**
A nowdoc string literal looks like a [heredoc string literal](09-lexical-structure.md#heredoc-string-literals) except that in the former the start identifier name is
enclosed in single quotes ('). The two forms of string literal have the
same semantics and constraints except that a nowdoc string literal is
not subject to variable substitution.
A nowdoc string literal is a [c-constant](06-constants.md#general).
**Examples**
```Hack
$v = 123;
$s = <<< 'ID'
S'o'me "\"t e\txt; \$v = $v"
Some more text
ID;
echo ">$s<\n\n";
→ >S'o'me "\"t e\txt; \$v = $v"
Some more text<
```
##### The Null Literal
null-literal::
null
**Semantics**
There is one null-literal value, `null`.
A *null-literal* has the null type.
#### Operators and Punctuators
**Syntax**
operator-or-punctuator:: one of
[ ] ( ) { } . -> ++ -- ** * + - ~ !
$ / % << >> < > <= >= == === != !== ^ |
& && || ? ?? : ; = **= *= /= %= += -= .= <<=
>>= &= ^= |= , @ :: => ==> ?-> \ ... |> $$
**Semantics**
Operators and punctuators are symbols that have independent syntactic
and semantic significance. *Operators* are used in expressions to
describe operations involving one or more *operands*, and that yield a
resulting value, produce a side effect, or some combination thereof.
*Punctuators* are used for grouping and separating.
================================================
FILE: spec/10-expressions.md
================================================
# Expressions
## General
An *expression* involves one or more terms and zero or more operators.
A *full expression* is an expression that is not part of another
expression.
A *value side effect* is an action that changes the state of the execution
environment. (Examples of such actions are modifying a variable, writing
to a device or file, or calling a function that performs such
operations.) Throughout this specification, this term is shortened to
*side effect*, which should not be confused with [*type side effect*](05-types.md#type-side-effects).
When an expression is evaluated, it produces a result. It might also
produce a side effect. Only a few operators produce side effects. (For
example, given the [expression statement](11-statements.md#expression-statements) `$v = 10`; the
expression 10 is evaluated to the result 10, and there is no side
effect. Then the assignment operator is executed, which results in the
side effect of `$v` being modified. The result of the whole expression is
the value of `$v` after the assignment has taken place. However, that
result is never used. Similarly, given the expression statement `++$v`;
the expression is evaluated to the result incremented-value-of-`$v`, and
the side effect is that `$v` is actually incremented. Again, the result
is never used.)
The occurrence of value computation and side effects is delimited by
*sequence points*, places in a program's execution at which all the
computations and side effects previously promised are complete, and no
computations or side effects of future operations have yet begun. There
is a sequence point at the end of each full expression. The [logical and](10-expressions.md#logical-and-operator), [logical or](10-expressions.md#logical-inclusive-or-operator), [conditional](10-expressions.md#conditional-operator), and [function-call](#function-call-operator) operators each contain a sequence point. (For example, in the
following series of expression statements, `$a = 10; ++$a; $b = $a;`,
there is sequence point at the end of each full expression, so the
assignment to $a is completed before `$a` is incremented, and the
increment is completed before the assignment to `$b`.)
When an expression contains multiple operators, the *precedence* of
those operators controls the order in which those operators are applied.
(For example, the expression `$a - $b / $c` is evaluated as
`$a - ($b / $c)` because the / operator has higher precedence than the
binary - operator.) The precedence of an operator is defined by the
definition of its associated grammar production.
If an operand occurs between two operators having the same precedence,
the order in which the operations are performed is defined by those
operators' *associativity*. With *left-associative* operators,
operations are performed left-to-right. (For example, `$a + $b - $c` is
evaluated as `($a + $b) - $c.`) With *right-associative* operators,
operations are performed right-to-left. (For example, `$a = $b = $c` is
evaluated as `$a = ($b = $c)`.)
Precedence and associativity can be controlled using *grouping
parentheses*. (For example, in the expression `($a - $b) / $c`, the
subtraction is done before the division. Without the grouping
parentheses, the division would take place first.)
While precedence, associativity, and grouping parentheses control the
order in which operators are applied, they do *not* control the order of
evaluation of the terms themselves. Unless stated explicitly in this
specification, the order in which the operands in an expression are
evaluated relative to each other is unspecified. See the discussion
above about the operators that contain sequence points. (For example, in
the full expression `$list1[$i] = $list2[$i++]`, whether the value
of `$i` on the left-hand side is the old or new `$i`, is unspecified.
Similarly, in the full expression `$j = $i + $i++`, whether the value
of `$i` is the old or new `$i`, is unspecified. Finally, in the full
expression `f() + g() * h()`, the order in which the three functions are
called, is unspecified.)
**Implementation Notes**
An expression that contains no side effects and whose resulting value is
not used need not be evaluated. For example, the expression statements
`6;, $i + 6;`, and `$i/$j`; are well formed, but they contain no side
effects and their results are not used.
A side effect need not be executed if it can be defined that no other
program code relies on its having happened. (For example, in the cases
of return `$a++`; and return `++$a`;, it is obvious what value must be
returned in each case, but if `$a` is a variable local to the enclosing
function, `$a` need not actually be incremented.
## Restrictions on Arithmetic Operations
No arithmetic operation can be performed on the value `null` or on a value of
type `bool`, `string` (not even if the string is numeric), or any nullable type (including nullable arithmetic types).
## Operations on Operands Having One or More Subtypes
None of the subclauses in this Expressions clause discuss the use of operands
of supertypes such as `num`, `arraykey`, or `?int`. Refer to [§§](05-types.md#type-side-effects) for a discussion of type side effects.
## Primary Expressions
### General
**Syntax**
primary-expression:
variable-name
qualified-name
literal
const-expression
intrinsic
collection-literal
tuple-literal
shape-literal
anonymous-function-creation-expression
awaitable-creation-expression
( expression )
$this
$$
**Defined elsewhere**
* [*anonymous-function-creation-expression*](10-expressions.md#anonymous-function-creation)
* [*awaitable-creation-expression*](10-expressions.md#async-blocks)
* [*collection-literal*](10-expressions.md#collection-literals)
* [*const-expression*](10-expressions.md#constant-expressions)
* [*expression*](10-expressions.md#yield-operator)
* [*intrinsic*](10-expressions.md#general-2)
* [*literal*](09-lexical-structure.md#general-2)
* [*qualified-name*](20-namespaces.md#defining-namespaces)
* [*shape-literal*](10-expressions.md#shape-literals)
* [*tuple-literal*](10-expressions.md#tuple-literals)
* [*variable-name*](09-lexical-structure.md#names)
**Semantics**
The type and value of a parenthesized expression are identical to those of
the un-parenthesized expression.
The variable `$this` is predefined inside any instance method,
constructor, or destructor when that method is called from within an object
context. `$this` is a [handle](05-types.md#general) that points to the calling
object or to the object being constructed. The type of `$this` is
[`this`](05-types.md#the-this-type). `$this` is a non-modifiable lvalue.
The *pipe variable* `$$` is predefined only within the
*coalesce-expression* of a
[*piped-expression*](10-expressions.md#pipe-operator). The type and value of
`$$` is the type and value of that *coalesce-expression*. `$$` is a
non-modifiable lvalue.
### Intrinsics
#### General
**Syntax**
intrinsic:
array-intrinsic
echo-intrinsic
exit-intrinsic
invariant-intrinsic
list-intrinsic
**Defined elsewhere**
* [*array-intrinsic*](10-expressions.md#array)
* [*echo-intrinsic*](10-expressions.md#echo)
* [*exit-intrinsic*](10-expressions.md#exit)
* [*invariant-intrinsic*](10-expressions.md#invariant)
* [*list-intrinsic*](10-expressions.md#list)
**Semantics**
The names in this series of subclauses are reserved and are
called *intrinsics*. These names are not keywords; nor are they functions.
Note: The initial Hack execution environment was built on top of that for PHP,
which has an intrinsic called `empty`. And even though an intrinsic by that
name is not supported by Hack strict mode, the case-indistinct name `empty` is
reserved in Hack as well.
#### array
**Syntax**
array-intrinsic:
array ( array-initializeropt )
**Defined elsewhere**
* [*array-initializer*](10-expressions.md#array-creation-operator)
**Semantics**
This intrinsic creates and initializes an array. It is equivalent to the
[array-creation operator `[]`](10-expressions.md#array-creation-operator).
#### echo
**Syntax**
echo-intrinsic:
echo expression
echo ( expression )
echo expression-list-two-or-more
expression-list-two-or-more:
expression , expression
expression-list-two-or-more , expression
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
**Constraints**
*expression* must not designate an array nor an instance of a type not
having a [`__toString` method](16-classes.md#method-__tostring).
**Semantics**
After converting each of its *expression*s' values to strings, if
necessary, `echo` concatenates them in lexical order, and writes the
resulting string to [`STDOUT`](05-types.md#resource-types).
For value substitution in string literals, see [§§](09-lexical-structure.md#double-quoted-string-literals) and
[§§](09-lexical-structure.md#heredoc-string-literals). For conversion to string, see [§§](08-conversions.md#converting-to-string-type).
**Examples**
```Hack
$v1 = true;
$v2 = 123;
echo '>>' . $v1 . '|' . $v2 . "<<\n"; // outputs ">>1|123<<"
echo '>>' , $v1 , '|' , $v2 , "<<\n"; // outputs ">>1|123<<"
echo ('>>' . $v1 . '|' . $v2 . "<<\n"); // outputs ">>1|123<<"
$v3 = "qqq{$v2}zzz";
echo "$v3\n";
```
#### exit
**Syntax**
exit-intrinsic:
exit expressionopt
exit ( expressionopt )
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
**Constraints**
When *expression* designates an integer, its value must be in the range
0–254.
**Semantics**
This intrinsic terminates the current script. If *expression* designates
a string, that string is written to [`STDOUT`](05-types.md#resource-types). If *expression*
designates an integer, that represents the script's *exit status code*.
Code 255 is reserved by Hack. Code 0 represents "success". The exit
status code is made available to the execution environment. If
*expression* is omitted or is a string, the exit status code is zero.
`exit` does not have a resulting value.
`exit` performs the following operations, in order:
- Writes the optional string to `STDOUT`.
- Calls any functions registered via the library function
[`register_shutdown_function`](http://www.php.net/register_shutdown_function) in their order of registration.
- Invokes [destructors](16-classes.md#destructors) for all remaining instances.
**Examples**
```Hack
exit ("Closing down");
exit (1);
exit;
```
#### invariant
**Syntax**
invariant-intrinsic:
invariant ( condition , format )
invariant ( condition , format , values )
**Constraints**
*condition* can be any expression allowed as the operand of the [`!` operator](10-expressions.md#unary-arithmetic-operators). *format* is a string that can contain text and/or optional
formatting information as understood by the library function [`sprintf`](http://www.php.net/sprintf).
The optional comma-separated list of values designated by *values* must match
the set of types expected by the optional formatting information inside
*format*.
**Semantics**
If *condition* tests true, the program continues execution; otherwise, the
library function [`invariant_violation`](http://www.php.net/invariant_violation) is called. That function does not
return; instead, it either throws an exception of type
`\HH\InvariantException`, or calls the handler previously registered by the
library function [`invariant_callback_register`](http://www.php.net/invariant_callback_register).
This intrinsic behaves like a function with a `void` return type. It is
intended to indicate a programmer error for a condition that should never
occur.
**Examples**
```Hack
invariant($interf instanceof B, "Object must have type B");
// -----------------------------------------
invariant(!is_null($p), "Value can't be null");
// -----------------------------------------
$max = 100;
invariant(!is_null($p) && $p <= $max, "Value %d must be <= %d", $p, $max);
```
#### list
**Syntax**
list-intrinsic:
list ( list-expression-listopt )
list-expression-list:
expression
,
list-expression-list , expressionopt
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
**Constraints**
*list-intrinsic* must be used as the left-hand operand in a
[*simple-assignment-expression*](10-expressions.md#simple-assignment) of which the right-hand
operand must be an expression that designates a vector-like array or an instance of the class types `Vector`, `ImmVector`, or `Pair` (the
"source").
Each *expression* in *list-expression-list* must designate a
variable (the "target variable").
There must not be fewer element candidates in the source than there are target
variables.
Only the right-most *list-or-variable* can be omitted.
**Semantics**
This intrinsic assigns zero or more elements of the source to the
target variables. On success, it returns a copy of the source.
When the source is a vector-like array, the element having an `int` key of 0 is assigned to the first target
variable, the element having an `int` key of 1 is assigned to the second
target variable, and so on, until all target variables have been
assigned. Any elements having an `int` key outside the range 0–(*n*-1),
where *n* is the number of target variables, are ignored.
If ([`$_`](09-lexical-structure.md#names) is used as a target variable, the value of the corresponding source element is ignored; no assignment takes place. Multiple target variables in the same list-expression-list may be `$_`.
When the source is an instance of the classes `Vector`, `ImmVector`, or `Pair`, the
elements in the source are assigned to the target variables in lexical order,
until all target variables have been assigned.
If the source elements and the target variables overlap in any
way, the behavior is unspecified.
**Examples**
```Hack
// $min, $max, and $avg must be defined at this point
list($min, $max, $avg) = array(0, 100, 67);
// $min is 0, $max is 100, $avg is 67
$a = array();
$v = list($a[0], $a[2], $a[4]) = array(50, 5100, 567);
// $a[0] is 50, $a[2] is 5100, $a[4] is 567
list($min, $max, ) = array(10, 1100, 167);
// $min is 10, $max is 1100
$v = Vector {1, 2, 3};
list($_, $b, $_) = $v; // $b is assigned 2; 1 and 3 are ignored
```
### Collection Literals
Note: The term *literal* as used here is a misnomer; *cl-element-keys* and
*cl-element-values* need not be compile-time constants.
**Syntax**
collection-literal:
non-key-collection-class-type { cl-initializer-list-without-keysopt }
key-collection-class-type { cl-initializer-list-with-keysopt }
pair-type { cl-element-value , cl-element-value }
non-key-collection-class-type:
qualified-name
key-collection-class-type:
qualified-name
pair-type:
qualified-name
cl-initializer-list-without-keys:
cl-element-value
cl-initializer-list-without-keys , cl-element-value
cl-initializer-list-with-keys:
cl-element-key => cl-element-value
cl-initializer-list-with-keys , cl-element-key => cl-element-value
cl-element-key:
expression
cl-element-value:
expression
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
**Constraints**
For *key-collection-class-type*, *qualified-name* must designate the library
type `Map` or `ImmMap`, and in both cases, each *cl-element-key* must have
type `int` or `string`.
For *key-collection-class-type*, *qualified-name* must designate the library
type `Vector`, `ImmVector`, `Set`, or `ImmSet`, and in all such cases, each
*cl-element-value* must have type `int` or `string`.
For *pair-type*, *qualified-name* must designate the library type `Pair`.
**Semantics**
For *non-key-collection-class-types* `Vector` and `ImmVector`, an instance of
the corresponding class is created with elements having values as specified by
*cl-initializer-list-without-keys*, inserted in that order, and assigned
consecutive keys starting at zero. If *cl-initializer-list-without-keys* is
omitted, the resulting vector is empty.
For *non-key-collection-class-types* `Map` and `ImmMap`, an instance of the
corresponding class is created with elements having keys and values as
specified by *cl-initializer-list-with-keys*, inserted in that order. If
*cl-initializer-list-with-keys* is omitted, the resulting map is empty. If two
or more *cl-element-keys* in a *cl-initializer-list-with-keys* contain the
same key, the lexically right-most one is the one whose *cl-element-value* is
used to initialize the element designated by that key.
For *non-key-collection-class-types* `Set` and `ImmSet`, an instance of the
corresponding class is created with elements having values as specified by
*cl-initializer-list-without-keys*, inserted in that order. If
*cl-initializer-list-without-keys* is omitted, the resulting set is empty.
Duplicate *cl-element-values* are ignored.
For type `Pair`, an instance of that class is created with element 0 having
the value of the left-hand *cl-element-value*, and element 1 having the value
of the right-hand *cl-element-value*.
**Examples**
```Hack
Vector {22, 33} // size 2; 22, 33
(Vector {})->addAll(array(3, 6, 9)) // size 0 then size 3; 3, 6, 9
ImmVector {5, $x, 15} // size 3; 5, ?, 15
Map {'x' => -1, 'a' => -4, 'x' => 5, 'a' => 12} // size 2; 'x'/5, 'a'/12
ImmSet {1, 1, 1, 5, 10, 1, 'red', 1} // size 4; 1, 5, 10, 'red'
Pair {55, new C()}
```
### Tuple Literals
Note: The term *literal* as used here is a misnomer; the *expression*s in
*expression-list* need not be compile-time constants.
**Syntax**
tuple-literal: tuple ( expression-list-one-or-more ) expression-list-one-or-more: expression expression-list-one-or-more , expression**Defined elsewhere** * [*expression*](10-expressions.md#yield-operator) **Semantics** A *tuple-literal* creates a [tuple](05-types.md#tuple-types) with elements having values as specified by *expression-list-one-or-more*, inserted in that order. The type of a *tuple-literal* is "tuple of type <*element type list in lexical order*>". Note: Although a tuple of only one element can be created using a tuple literal, a [*tuple-type-specifier*](05-types.md#tuple-types) must contain at least two elements. **Examples** ```Hack return tuple(true, array(99, 88, 77), 10.5); $t1 = tuple(10, true, 2.3, 'abc', null, $p1, Vector {$p2 + 3, 12}, new C()); $t2 = tuple(100, tuple('abc', false)); ``` ### Shape Literals Note: The term *literal* as used here is a misnomer; the *expression*s in *field-initializer* need not be compile-time constants. **Syntax**
shape-literal:
shape ( field-initializer-listopt )
field-initializer-list:
field-initializers ,opt
field-initializers:
field-initializer
field-initializers , field-initializer
field-initializer:
single-quoted-string-literal => expression
integer-literal => expression
qualified-name => expression
scope-resolution-expression => expression
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
* [*integer-literal*](09-lexical-structure.md#integer-literals)
* [*qualified-name*](20-namespaces.md#defining-namespaces)
* [*scope-resolution-expression*](10-expressions.md#scope-resolution-operator)
* [*single-quoted-string-literal*](09-lexical-structure.md#single-quoted-string-literals)
**Constraints**
Each string in the set of strings designated by all the
*single-quoted-string-literals*, *qualified-names* and *scope-resolution-expressions* in a
*field-initializer-list* must have a distinct value, and each string must
match exactly a field name in the shape type's [*shape-specifier*](05-types.md#shape-types).
Each integer in the set of *integer-literals*, *qualified-names* and *scope-resolution-expressions* in a
*field-initializer-list* must have a distinct value, and each integer must
match exactly a field name in the shape type's *shape-specifier*.
The number of *field-initializers* must match exactly the number of
*field-specifiers* in the shape type's *shape-specifier*.
The type of *expression* in a *field-initializer* must be a subtype of the
corresponding field type in the shape type's *shape-specifier*.
**Semantics**
A *shape-literal* creates a [shape](05-types.md#shape-types) with fields having values as specified by *field-initializer-list*. The order of the
*field-initializers* need not be the same as the order of the
*field-specifiers* in the shape type's *shape-specifier*.
**Examples**
```Hack
shape()
shape('x' => $prevX, 'y' => getY())
shape('id' => null, 'url' => null, 'count' => 0)
```
### Anonymous Function-Creation
**Syntax**
anonymous-function-creation-expression: asyncopt function ( anonymous-function-parameter-listopt ) anonymous-function-returnopt anonymous-function-use-clauseopt compound-statement anonymous-function-parameter-list: ... anonymous-function-parameter-declaration-list anonymous-function-parameter-declaration-list , anonymous-function-parameter-declaration-list , ... anonymous-function-parameter-declaration-list: anonymous-function-parameter-declaration anonymous-function-parameter-declaration-list , anonymous-function-parameter-declaration anonymous-function-parameter-declaration: attribute-specificationopt type-specifieropt variable-name default-argument-specifieropt anonymous-function-return: : return-type anonymous-function-use-clause: use ( use-variable-name-list ,opt ) use-variable-name-list: variable-name use-variable-name-list , variable-name**Defined elsewhere** * [*attribute-specification*](20-namespaces.md#name-lookup) * [*compound-statement*](11-statements.md#compound-statements) * [*default-argument-specifier*](15-functions.md#function-definitions) * [*return-type*](15-functions.md#function-definitions) * [*type-specifier*](05-types.md#general) * [*variable-name*](09-lexical-structure.md#names) **Constraints** Each *variable-name* in an *anonymous-function-parameter-declaration-list* must be distinct. If any *anonymous-function-parameter-declaration* has a *default-argument-specifier*, then all subsequent *anonymous-function-parameter-declarations* in the same *anonymous-function-parameter-declaration-list* must also have a *default-argument-specifier*. If the *type-specifier* in *anonymous-function-return* is `void`, the *compound-statement* must not contain any [`return` statements](11-statements.md#the-return-statement) having an *expression*. Otherwise, all `return` statements must contain an *expression* whose type is a subtype of the type indicated by *type-specifier*. If `async` is present, *return-type* must be a type that implements [`Awaitable
awaitable-creation-expression:
async { async-statement-listopt }
async-statement-list:
statement
async-statement-list statement
**Defined elsewhere**
* [*statement*](11-statements.md#general)
**Constraints**
*awaitable-creation-expression* must not be used as the *lambda-body* in a [*lambda-expression*](10-expressions.md#lambda-expressions).
**Semantics**
The (possibly) asynchronous operations designated by *async-statement-list* are executed, in order.
An *awaitable-creation-expression* produces a result of type [`Awaitable
postfix-expression:
primary-expression
clone-expression
object-creation-expression
array-creation-expression
subscript-expression
function-call-expression
member-selection-expression
null-safe-member-selection-expression
postfix-increment-expression
postfix-decrement-expression
scope-resolution-expression
exponentiation-expression
**Defined elsewhere**
* [*array-creation-expression*](10-expressions.md#array-creation-operator)
* [*clone-expression*](10-expressions.md#the-clone-operator)
* [*exponentiation-expression*](10-expressions.md#exponentiation-operator)
* [*function-call-expression*](10-expressions.md#function-call-operator)
* [*member-selection-expression*](10-expressions.md#member-selection-operator)
* [*null-safe-member-selection-expression*](10-expressions.md#null-safe-member-selection-operator)
* [*object-creation-expression*](10-expressions.md#the-new-operator)
* [*postfix-decrement-expression*](10-expressions.md#postfix-increment-and-decrement-operators)
* [*postfix-increment-expression*](10-expressions.md#postfix-increment-and-decrement-operators)
* [*primary-expression*](10-expressions.md#general-1)
* [*scope-resolution-expression*](10-expressions.md#scope-resolution-operator)
* [*subscript-expression*](10-expressions.md#subscript-operator)
**Semantics**
These operators associate left-to-right.
### The `clone` Operator
**Syntax**
clone-expression:
clone expression
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
**Constraints**
*expression* must designate an object.
**Semantics**
The `clone` operator creates a new object that is a [shallow copy](04-basic-concepts.md#cloning-objects) of the object designated by *expression*. Then, if the class type of *expression* has a method called [`__clone`](16-classes.md#method-__clone), that is called to perform a [deep copy](04-basic-concepts.md#cloning-objects). The result is a handle that points to the new object.
**Examples**
Consider a class `Employee`, from which is derived a class `Manager`. Let us
assume that both classes contain properties that are objects. clone is
used to make a copy of a Manager object, and behind the scenes, the
`Manager` object uses clone to copy the properties for the base class,
`Employee`.
```Hack
class Employee
{
...
public function __clone(): void {
// make a deep copy of Employee object
}
}
class Manager extends Employee
{
...
public function __clone(): void
{
$v = parent::__clone();
// make a deep copy of Manager object
}
}
$obj1 = new Manager("Smith", 23);
$obj2 = clone $obj1; // creates a new Manager that is a deep copy
```
### The `new` Operator
**Syntax**
object-creation-expression:
new class-type-designator ( argument-expression-listopt )
class-type-designator:
parent
self
static
member-selection-expression
null-safe-member-selection-expression
qualified-name
scope-resolution-expression
subscript-expression
variable-name
**Defined elsewhere**
* [*argument-expression-list*](10-expressions.md#function-call-operator)
* [*member-selection-expression*](10-expressions.md#member-selection-operator)
* [*null-safe-member-selection-expression*](10-expressions.md#null-safe-member-selection-operator)
* [*qualified-name*](20-namespaces.md#defining-namespaces)
* [*scope-resolution-expression*](10-expressions.md#scope-resolution-operator)
* [*subscript-expression*](10-expressions.md#subscript-operator)
* [*variable-name*](09-lexical-structure.md#names)
**Constraints**
If the *class-type-designator* is a *scope-resolution-expression* then it must not have `class` as the right hand side of the `::` operator.
Otherwise, if the *class-type-designator* is a *qualified-name* or *scope-resolution-expression* which resolves a qualified name, or `self`, or `parent`, then it must designate a class.
Otherwise,the *class-type-designator* must be an expression evaluating to a value having the [`classname` type](05-types.md#the-classname-type). Furthermore, it must designate a class that has the attribute [`__ConsistentConstruct`](21-attributes.md#attribute-__consistentconstruct), or that has an abstract constructor or a final constructor.
The *class-type-designator* must not designate an [abstract class](16-classes.md#general).
The *class-type-designator* must not be a [generic type parameter](14-generic-types-methods-and-functions.md#type-parameters).
The *object-creation-expression* will invoke the constructor of the class designated by the *class-type-designator*.
*argument-expression-list* must contain an argument for each parameter in the
[constructor's definition](15-functions.md#function-definitions) not having a default value, and each
argument's type must be a subtype of the corresponding parameter's type.
If the constructor is not variadic, the call must not contain more arguments
than there are corresponding parameters.
**Semantics**
The `new` operator allocates memory for an object that is an instance of
the class specified by the *class-type-designator*.
The object is initialized by calling the class's constructor (16.8)
passing it the optional *argument-expression-list*. If the class has no
constructor, the constructor that class inherits (if any) is used.
Otherwise, each instance property having any nullable type takes on the value
`null`.
The result of an *object-creation-expression* is a handle to an object
of the type specified by the *class-type-designator*.
From within a method, the use of `static` corresponds to the class in the
inheritance context in which the method is called. The type of the object created by an expression of the form `new static` is [`this`](05-types.md#the-this-type).
Because a constructor call is a function call, the relevant parts of
10.5.6 also apply.
**Examples**
```Hack
class Point
{
public function __construct(float $x = 0, float $y = 0)
{
...
}
...
}
$p1 = new Point(); // create Point(0, 0)
$p1 = new Point(12); // create Point(12, 0)
// -----------------------------------------
class C { ... }
function f(classname
array-creation-expression:
array ( array-initializeropt )
[ array-initializeropt ]
array-initializer:
array-initializer-list ,opt
array-initializer-list:
array-element-initializer
array-element-initializer , array-initializer-list
array-element-initializer:
element-value
element-key => element-value
element-key:
expression
element-value
expression
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
**Constraints**
If any *array-element-initializer* in an *array-initializer-list* contains
an *element-key*, then all *array-element-initializers* in that
*array-initializer-list* must contain an *element-key*.
**Semantics**
This operator creates an array. If *array-initializer* contains any
*element-keys*, the resulting array is a map-like array; otherwise, it is a
vector-like array. If *array-initializer* is omitted, the array has zero elements, and the resulting array is neither a vector-like nor a map-like
array, although it is a subtype of both types.. For convenience, an
*array-initializer* may have a trailing comma; however, this comma has no
purpose. An *array-initializer-list* consists of a vector-like array. If
*array-initializer* is omitted, the array has zero elements. For convenience,
an *array-initializer* may have a trailing comma; however, this comma has no
purpose. An *array-initializer-list* consists of a comma-separated list of
one or more *array-element-initializer*s, each of which is used to provide an
*element-value* and an optional *element-key*.
If the value of *element-key* is neither `int` nor `string`, keys with `float`
or `bool` values, or strings whose contents match exactly the pattern of
[*decimal-literal*](09-lexical-structure.md#integer-literals), are [converted to `int`](08-conversions.md#converting-to-integer-type), and values
of all other key types are [converted to `string`](08-conversions.md#converting-to-string-type).
If *element-key* is omitted from an *array-element-initializer*, an
element key of type `int` is associated with the corresponding
*element-value*. The key associated is one more than the previously
assigned `int` key for this array. However, if this is the first element
with an `int` key, key zero is associated.
Once the element keys have been converted to `int` or `string`, if two or more
*array-element-initializer*s in an *array-initializer* contain the same
key, the lexically right-most one is the one whose element-value is used
to initialize that element.
The result of this operator is a handle to the set of array elements.
**Examples**
```Hack
$v = []; // array has 0 elements
$v = array(true); // vector-like array has 1 element, true
$v = [123, -56]; // vector-like array of two ints, with keys 0 and 1
$v = [0 => 123, 1 => -56]; // map-like array of two ints, with keys 0 and 1
$i = 10;
$v = [$i - 10 => 123, $i - 9 => -56]; // key can be a runtime expression
$i = 6; $j = 12;
$v = [7 => 123, 3 => $i, 6 => ++$j]; // keys are in arbitrary order
$v[4] = 99; // extends array with a new element
$v = [2 => 23, 1 => 10, 2 => 46, 1.9 => 6];
// map-like array has 2 elements, with keys 2 and 1, values 46 and 6
$v = ["red" => 10, "4" => 3, 9.2 => 5, "12.8" => 111, null => 1];
// map-like array has 5 elements, with keys "red", 4, 9, "12.8", and "".
$c = array("red", "white", "blue");
$v = array(10, $c, null, array(false, null, $c));
$v = array(2 => true, 0 => 123, 1 => 34.5, -1 => "red");
foreach($v as $e) { … } // iterates over keys 2, 0, 1, -1
for ($i = -1; $i <= 2; ++$i) { … $v[$i] } // retrieves via keys -1, 0, 1, 2
```
### Subscript Operator
**Syntax**
subscript-expression:
postfix-expression [ expressionopt ]
postfix-expression { expressionopt } [Deprecated form]
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
* [*postfix-expression*](10-expressions.md#general-3)
**Constraints**
If *postfix-expression* designates a string, *expression* must not
designate a string.
*expression* can be omitted only if *subscript-expression* is used in a
modifiable-lvalue context and *postfix-expression* does not designate a
string.
If *subscript-expression* is used in a non-lvalue context, the element
being designated must exist.
When *postfix-expression* designates a vector-like array, *expression* must
have type `int`.
When *postfix-expression* designates a map-like array, elements cannot be appended using empty `[]`.
When *postfix-expression* designates a tuple, *expression* must be a constant.
When *postfix-expression* designates a shape, *expression* must be a
[*single-quoted-string-literal*](09-lexical-structure.md#single-quoted-string-literals) that specifies a key in that
shape's [*shape-specifier*](05-types.md#shape-types).
When postfix-expression designates an instance of a collection class:
* The deprecated form, `{ … }`, is not supported.
* `Vector` or `ImmVector`, *expression* must have type `int`.
* `Vector`, if *expression* is omitted, *subscript-expression* must be the
left-hand side of a [*simple-assignment-expression*](10-expressions.md#simple-assignment).
* `Map` or `ImmMap`, *expression* must have type `int` or `string`.
* `Map`, if *expression* is omitted, *subscript-expression* must be the
left-hand side of a *simple-assignment-expression* whose right-hand operand
has type `Pair`.
* `Set` or `ImmSet`, subscripting is not permitted.
* `Pair`, *expression* must be either the literal 0 or 1.
**Semantics**
A *subscript-expression* designates a (possibly non-existent) element of
an array, a string, a vector, a map, or a Pair. When *subscript-expression* designates an object of
a type that implements [`ArrayAccess`](17-interfaces.md#interface-arrayaccess), the minimal semantics are
defined below; however, they can be augmented by that object's methods
[`offsetGet`](17-interfaces.md#interface-arrayaccess) and [`offsetSet`](17-interfaces.md#interface-arrayaccess).
The element key is designated by *expression*. If the value of
*element-key* is neither `int` nor `string`, keys with `float` or `bool` values,
or strings whose contents match exactly the pattern of [*decimal-literal*](09-lexical-structure.md#integer-literals), are [converted to `int`](08-conversions.md#converting-to-integer-type), and values of all other key
types are [converted to `string`](08-conversions.md#converting-to-string-type).
If both *postfix-expression* and *expression* designate strings,
*expression* is treated as if it specified the `int` key zero instead.
A *subscript-expression* designates a modifiable lvalue if and only if
*postfix-expression* designates a modifiable lvalue.
*postfix-expression designates an array*
If *expression* is present, if the designated element exists, the type
and value of the result is the type and value of that element;
otherwise, the result is `null`.
If *expression* is omitted, a new element is inserted. Its key has type
`int` and is one more than the highest, previously assigned, non-negative
`int` key for this array. If this is the first element with a non-negative
`int` key, key zero is used. However, if the highest, previously assigned
`int` key for this array is [`PHP_INT_MAX`](06-constants.md#core-predefined-constants), **no new element is
inserted**. The type and value of the result is the type and value of
the new element.
* If the usage context is as the left-hand side of a [*simple-assignment-expression*](10-expressions.md#simple-assignment): The value of the new element is the value of the right-hand side of that *simple-assignment-expression*.
* If the usage context is as the left-hand side of a [*compound-assignment-expression*](10-expressions.md#compound-assignment): The expression `e1 op= e2` is evaluated as `e1 = null op (e2)`.
* If the usage context is as the operand of a [postfix-](10-expressions.md#postfix-increment-and-decrement-operators) or [prefix-increment or decrement operator](10-expressions.md#prefix-increment-and-decrement-operators): The value of the new element is `null`.
*postfix-expression designates a string*
If the designated element exists, the type and value of the result is
the type and value of that element; otherwise, the result is an empty
string.
*postfix-expression designates a vector*
For a `Vector` or `ImmVector`, if *expression* is present, if the designated
element exists, the type and value of the result is the type and value of that
element; otherwise, an exception of type `\OutOfBoundsException` is thrown.
For a `Vector`, if *expression* is omitted, a new element is inserted whose
value is that of the right-hand side of the *simple-assignment-expression*.
Its key has type `int` and is one more than the highest, previously assigned,
`int` key for this `Vector`. If this is the first element, key zero is used.
The type and value of the result is the type and value of the new element.
*postfix-expression designates a map*
For a `Map` or `ImmMap`, if *expression* is present, if the designated element
exists, the type and value of the result is the type and value of that
element; otherwise, an exception of type `\OutOfBoundsException` is thrown.
For a `Map`, if *expression* is omitted, the contents of the `Pair` right-hand
operand of the *simple-assignment-expression* for which this
*subscript-expression* is the left operand, is examined. Element 0 of that
Pair represents the key while element 1 represents the value. If the Map
already contains an element having that key, that element's value is changed
to the value in the Pair; otherwise, a new element is inserted in the Map with
the key and value from the Pair. The type and value of the result is the type
and value of the modified or new element.
*postfix-expression designates a Pair*
If *expression* is the literal 0, the type and value of the result is the type
and value of the first element in that `Pair`.
If *expression* is the literal 1, the type and value of the result is the type
and value of the second element in that `Pair`.
*postfix-expression designates an object of a type that implements*
`ArrayAccess`
If *expression* is present,
* If *subscript-expression* is used in a non-lvalue context, the object's method `offsetGet` is called with an argument of *expression*. The type and value of the result is the type and value returned by `offsetGet`.
* If the usage context is as the left-hand side of a *simple-assignment-expression*: The object's method `offsetSet` is called with a first argument of *expression* and a second argument that is the value of the right-hand side of that *simple-assignment-expression*. The type and value of the result is the type and value of the right-hand side of that *simple-assignment-expression*.
* If the usage context is as the left-hand side of a *compound-assignment-expression*: The expression `e1 op= e2` is evaluated as `e1 = offsetGet(expression) op (e2)`, which is then processed according to the rules for simple assignment immediately above.
* If the usage context is as the operand of a [postfix-](10-expressions.md#postfix-increment-and-decrement-operators) or [prefix-increment or decrement operator](10-expressions.md#prefix-increment-and-decrement-operators): The object's method `offsetGet` is called with an argument of *expression*. However, this method has no way of knowing if an increment or decrement operator was used, or whether it was a prefix or postfix operator. The type and value of the result is the type and value returned by `offsetGet`.
If *expression* is omitted,
* If the usage context is as the left-hand side of a *simple-assignment-expression*: The object's method [`offsetSet`](15-interfaces.md#interface-arrayaccess) is called with a first argument of `null` and a second argument that is the value of the right-hand side of that *simple-assignment-expression*. The type and value of the result is the type and value of the right-hand side of that *simple-assignment-expression*.
* If the usage context is as the left-hand side of a *compound-assignment-expression*: The expression `e1 op= e2` is evaluated as `e1 = offsetGet(null) op (e2)`, which is then processed according to the rules for simple assignment immediately above.
* If the usage context is as the operand of a [postfix-](10-expressions.md#postfix-increment-and-decrement-operators) or [prefix-increment or decrement operator](10-expressions.md#prefix-increment-and-decrement-operators): The object's method `offsetGet` is called with an argument of `null`. However, this method has no way of knowing if an increment or decrement operator was used, or whether it was a prefix or postfix operator. The type and value of the result is the type and value returned by `offsetGet`.
Note: The brace (`{...}`) form of this operator has been deprecated.
**Examples**
```Hack
$v = array(10, 20, 30);
$v[1] = 1.234; // change the value (and type) of element [1]
$v[-10] = 19; // insert a new element with int key -10
$v["red"] = true; // insert a new element with string key "red"
[[2,4,6,8], [5,10], [100,200,300]][0][2] // designates element with value 6
["black", "white", "yellow"][1][2] // designates substring "i" in "white"
function f(): array
function-call-expression:
postfix-expression ( argument-expression-listopt )
argument-expression-list:
argument-expressions ,opt
argument-expressions:
expression
argument-expressions , expression
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
* [*postfix-expression*](10-expressions.md#general-3)
**Constraints**
*postfix-expression* must designate a function, by *name*, be a variable of
[closure type](05-types.md#closure-types).
The function call must contain an argument for each parameter in the called
[function's definition](15-functions.md#function-definitions) not having a default value, and the argument
type must be a subtype of the parameter type.
If the called function is not variadic, the function call must not contain
more arguments than there are corresponding parameters.
**Semantics**
If *postfix-expression* is a [*null-safe-member-selection-expression*](10-expressions.md#null-safe-member-selection-operator), special handling occurs; see later below.
An expression of the form *function-call-expression* is a *function
call*. The postfix expression designates the *called function*, and
*argument-expression-list* specifies the arguments to be passed to that
function. Each argument corresponds to a parameter or the optional ellipsis in
the called function's definition. An argument can have any type. In a function
call, *postfix-expression* is evaluated first, followed by each
*assignment-expression* in the order left-to-right. There is a [sequence
point](#general) right before the function is called. For details of the
type and value of a function call see [§§](11-statements.md#the-return-statement). The value of a function
call, if any, is a non-modifiable lvalue.
If the called function is variadic, the function call can have any number of
arguments, provided the function call has at least an argument for each
parameter not having a default value.
When an argument corresponds to the ellipsis in the called function's
definition, the argument can have any type.
When *postfix-expression* designates an instance method or constructor,
the instance used in that designation is used as the value of `$this` in
the invoked method or constructor. However, if no instance was used in
that designation (for example, in the call `C::instance_method()`) the
invoked instance has no `$this` defined.
When a function is called, the value of each argument passed to it is
assigned to the corresponding parameter in that function's definition,
if such a parameter exists. The assignment of argument values to
parameters is defined in terms of [simple assignment](10-expressions.md#simple-assignment). Any parameters having a
default value but no corresponding argument, takes on that default value.
If an undefined variable is passed using byRef, that variable becomes
defined, with a default value of `null`.
Direct and indirect recursive function calls are permitted.
The following discussion applies when *postfix-expression* is a
*null-safe-member-selection-expression*: If *postfix-expression* is not
`null`, the behavior is the same as if a [*member-selection-expression*](10-expressions.md#member-selection-operator) were used instead of a *null-safe-member-selection-expression*.
Otherwise, no function is called, and the *function-call-expression*
evaluates to `null`. The *expression*s in
*argument-expression-list* are evaluated.
**Examples**
```Hack
function f3(int $p1 = -1, float $p2 = 99.99, string $p3 = '??'): void { … }
f3(); // $p1 is -1, $p2 is 99.99, $p3 is ??
f3(123); // $p1 is 123, $p2 is 99.99, $p3 is ??
f3(123, 3.14); // $p1 is 123, $p2 is 3.14, $p3 is ??
f3(123, 3.14, 'Hello'); // $p1 is 123, $p2 is 3.14, $p3 is Hello
// -----------------------------------------
function fx(int $p1, int $p2, int $p3, int $p4, int $p5): void { … }
function fy(int $p1, int $p2, int $p3, int $p4, int $p5): void { … }
function fz(int $p1, int $p2, int $p3, int $p4, int $p5): void { … }
$funcTable = array(fun('fx'), fun('fy'), fun('fz')); // use lib function fun
$i = 1;
$funcTable[$i++]($i, ++$i, $i, $i = 12, --$i); // calls fy(2,3,3,12,11)
// -----------------------------------------
$anon = function (): void { … }; // store a closure in $anon
$anon(); // call the anonymous function
```
### Member-Selection Operator
**Syntax**
member-selection-expression:
postfix-expression -> name
postfix-expression -> variable-name
**Defined elsewhere**
* [*name*](09-lexical-structure.md#names)
* [*postfix-expression*](10-expressions.md#general-3)
* [*variable-name*](09-lexical-structure.md#names)
**Constraints**
*postfix-expression* must designate an object.
*name* must designate an instance property, or an instance
method of the class designated by *postfix-expression*.
*variable-name* must name a variable which when evaluated produces a string
containing an instance property or an instance method of the class
designated by *postfix-expression*.
**Semantics**
A *member-selection-expression* designates an instance property or an
instance method of the object designated by
*postfix-expression*. For a property, the value is that of the property,
and is a modifiable lvalue if *postfix-expression* is a modifiable
lvalue.
**Examples**
```Hack
class Point {
private float $x;
private float $y;
public function move(float $x, float $y): void {
$this->x = $x; // sets private property $x
$this->y = $y; // sets private property $x
}
public function __toString(): string {
return '(' . $this->x . ',' . $this->y . ')';
} // get private properties $x and $y
}
$p1 = new Point();
$p1->move(3, 9); // calls public instance method move by name
```
### Null-Safe Member-Selection Operator
**Syntax**
null-safe-member-selection-expression: postfix-expression ?-> name postfix-expression ?-> variable-name**Defined elsewhere** * [*name*](09-lexical-structure.md#names) * [*postfix-expression*](10-expressions.md#general-3) * [*variable-name*](09-lexical-structure.md#names) **Constraints** *postfix-expression* must designate a nullable-typed object. *name* must designate an instance property or an instance method of the class designated by *postfix-expression*. *variable-name* must name a variable which when evaluated produces a string containing an instance property or an instance method of the class designated by *postfix-expression*. **Semantics** If *postfix-expression* is `null`, no property or method is selected and the resulting value is `null`. Otherwise, the behavior is like that of the [member-selection operator `->`](10-expressions.md#member-selection-operator), except that the resulting value is not an lvalue. ### Postfix Increment and Decrement Operators **Syntax**
postfix-increment-expression:
unary-expression ++
postfix-decrement-expression:
unary-expression --
**Defined elsewhere**
* [*unary-expression*](10-expressions.md#general-4)
**Constraints**
The operand of the postfix ++ and -- operators must be a modifiable
lvalue that has arithmetic type.
**Semantics**
These operators behave like their [prefix counterparts](10-expressions.md#prefix-increment-and-decrement-operators) except
that the value of a postfix ++ or -- expression is the value before any
increment or decrement takes place.
**Examples**
```Hack
$i = 10; $j = $i-- + 100; // old value of $i (10) is added to 100
$a = array(100, 200); $v = $a[1]++; // old value of $ia[1] (200) is assigned
```
### Scope-Resolution Operator
**Syntax**
scope-resolution-expression:
scope-resolution-qualifier :: name
scope-resolution-qualifier :: variable-name
scope-resolution-qualifier :: class
scope-resolution-qualifier:
qualified-name
variable-name
self
parent
static
**Defined elsewhere**
* [*name*](09-lexical-structure.md#names)
* [*qualified-name*](20-namespaces.md#defining-namespaces)
* [*variable-name*](09-lexical-structure.md#names)
**Constraints**
Scope resolution expressions of the form qualified-name`::`name must have the name of an enum, class or interface type on the left of the `::`, and an enumeration constant or type member on the right.
Scope resolution expressions of the form qualified-name`::`variable-name must have the name of a class or interface type on the left of the `::`, and a static property of that type on the right.
Scope resolution expressions of the form qualified-name`::`class must have the name of a class or interface type on the left of the `::`.
Scope resolution expressions with a *variable-name* to the left of the `::` must name a variable having the [`classname` type](05-types.md#the-classname-type).
*variable-name* `:: class` is not permitted.
**Semantics**
When *qualified-name* is the name of an enumerated type, *scope-resolution-expression* designates an enumeration constant within that type.
From inside or outside a class or interface, operator `::` allows the
selection of a constant. From inside or outside a class, this operator
allows the selection of a static property, static method, or instance
method. From within a class, it also allows the selection of an
overridden property or method. For a property, the value is that of the
property, and is a modifiable lvalue if *name* is
a modifiable lvalue.
From within a class, `self::m` refers to the member `m` in that class,
whereas `parent::m` refers to the closest member `m` in the base-class
hierarchy, not including the current class. From within a method,
`static::m` refers to the member `m` in the class that corresponds to the
class inheritance context in which the method is called. This allows
*late static binding*. Consider the following scenario:
```Hack
class Base
{
public function b(): void
{
static::f(); // calls the most appropriate f()
}
public function f(): void { ... }
}
class Derived extends Base
{
public function f(): void { ... }
}
$b1 = new Base();
$b1->b(); // as $b1 is an instance of Base, Base::b() calls Base::f()
$d1 = new Derived();
$d1->b(); // as $d1 is an instance of Derived, Base::b() calls Derived::f()
```
The value of the form of *scope-resolution-expression* ending in `::class`
is a string containing the fully qualified name of the current class,
which for a static qualifier, means the current class context.
*variable-name* `::` *name* results in a constant whose value has the [`classname` type](05-types.md#the-classname-type) for the type designated by *variable-name*.
**Examples**
```Hack
final class MathLibrary
enum ControlStatus: int {
Stopped = 0;
Stopping = 1;
Starting = 2;
Started = 3;
}
function main(ControlStatus $p1): void {
switch ($p1)
{
case ControlStatus::Stopped:
…
break;
case ControlStatus::Stopping:
…
break;
…
}
…
}
// -----------------------------------------
final class MathLibrary {
public static function sin(): float { … }
…
}
$v = MathLibrary::sin(2.34); // call directly by class name
// -----------------------------------------
class MyRangeException extends Exception {
public function __construct(string $message, …)
{
parent::__construct($message);
…
}
…
}
// -----------------------------------------
class Point {
private static int $pointCount = 0;
public static function getPointCount(): int {
return self::$pointCount;
}
…
}
```
### Exponentiation Operator
**Syntax**
exponentiation-expression:
expression ** expression
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
**Constraints**
Both *expression*s must have an arithmetic type.
**Semantics**
The `**` operator produces the result of raising the value of the
left-hand operand to the power of the right-hand one. If both operands have non-negative integer
values and the result can be represented as an `int`, the result has type
`int`; otherwise, the result has type `float`.
**Examples**
```Hack
2**3; // int with value 8
2**3.0; // float with value 8.0
"2.0"**"3"; // float with value 8.0
```
## Unary Operators
### General
**Syntax**
unary-expression:
postfix-expression
prefix-increment-expression
prefix-decrement-expression
unary-op-expression
error-control-expression
cast-expression
await-expression
**Defined elsewhere**
* [*await-expression*](10-expressions.md#await-operator)
* [*cast-expression*](10-expressions.md#cast-operator)
* [*error-control-expression*](10-expressions.md#error-control-operator)
* [*postfix-expression*](10-expressions.md#general-3)
* [*prefix-decrement-expression*](10-expressions.md#prefix-increment-and-decrement-operators)
* [*prefix-increment-expression*](10-expressions.md#prefix-increment-and-decrement-operators)
* [*unary-op-expression*](10-expressions.md#unary-arithmetic-operators)
**Semantics**
These operators associate right-to-left.
### Prefix Increment and Decrement Operators
**Syntax**
prefix-increment-expression:
++ unary-expression
prefix-decrement-expression:
-- unary-expression
**Defined elsewhere**
* [*unary-expression*](10-expressions.md#general-4)
**Constraints**
The operand of the prefix `++` or `--` operator must be a modifiable lvalue
that has arithmetic type.
**Semantics**
*Arithmetic Operands*
For a prefix `++` operator, the [side effect](#general) of the operator is to increment by 1, as appropriate, the
value of the operand. The result is the value of the operand after it
has been incremented. If an int operand's value is the largest
representable for that type, the type and value of [the result is implementation-defined](05-types.md#the-integer-type).
For a prefix `--` operator, the side
effect of the operator is to decrement by 1, as appropriate, the value
of the operand. The result is the value of the operand after it has been
decremented. If an int operand's value is the smallest representable for
that type, the type and value of [the result is implementation-defined](05-types.md#the-integer-type).
For a prefix `++` or `--` operator used with an operand having the value
`INF`, `-INF`, or `NAN`, there is no side effect, and the result is the
operand's value.
**Examples**
```Hack
$i = 10; $j = --$i + 100; // new value of $i (9) is added to 100
$a = array(100, 200); $v = ++$a[1]; // new value of $ia[1] (201) is assigned
```
### Unary Arithmetic Operators
**Syntax**
unary-op-expression:
unary-operator cast-expression
unary-operator: one of
+ - ! ~
**Defined elsewhere**
* [*cast-expression*](10-expressions.md#cast-operator)
**Constraints**
The operand of the unary `+` and unary `-` operators must have
arithmetic type.
The operand of the unary `!` operator must have arithmetic or enumerated type. (**The validity of allowing this operator to have an enumerated type operand is questionable; avoid such usage lest support for it disappears.**)
The operand of the unary `~` operator must have integer type.
**Semantics**
For a unary `+` operator, the type and
value of the result is the type and value of the operand.
For a unary `-` operator, the value of the
result is the negated value of the operand. However, if an int operand's
original value is the smallest representable for that type, the type and
value of [the result is implementation-defined](05-types.md#the-integer-type).
For a unary `!` operator, the type of the
result is `bool`. The value of the result is `true` if the value of the
operand is non-zero (or for a string-based enumeration, a non-empty string); otherwise, the value of the result is `false`. For
the purposes of this operator, `NAN` is considered a non-zero value. The
expression `!E` is equivalent to `(E == 0)`.
For a unary `~` operator, the type of the result
is `int`. The value of the result is the bitwise complement of the value
of the operand (that is, each bit in the result is set if and only if
the corresponding bit in the operand is clear).
**Examples**
```Hack
$v = +10;
if ($v1 > -5) ...
$t = true;
if (!$t) ...
$v = ~0b1010101;
```
### Error Control Operator
**Syntax**
error-control-expression:
@ expression
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
**Semantics**
Operator `@` suppresses any error messages generated by the evaluation of
*expression*.
If a custom error-handler has been established using the library
function [`set_error_handler`](http://docs.hhvm.com/manual/en/function.set-error-handler.php) that handler is
still called.
**Examples**
```Hack
$infile = @fopen("NoSuchFile.txt", 'r');
```
On open failure, the value returned by `fopen` is `false`, which is
sufficient to know to handle the error. There is no need to have any
error message displayed.
### Cast Operator
**Syntax**
cast-expression:
( cast-type ) unary-expression
cast-type: one of
bool int float string
**Defined elsewhere**
* [*unary-expression*](10-expressions.md#general-4)
**Semantics**
The
value of the operand *cast-expression* is converted to the type
specified by *cast-type*, and that is the type and value of the result.
This construct is referred to a *cast,* and is used as the verb, "to
cast". If no conversion is involved, the type and value of the result
are the same as those of *cast-expression*.
A cast can result in a loss of information.
A *cast-type* of `bool` results in a conversion to type `bool`.
See [§§](08-conversions.md#converting-to-boolean-type) for details.
A *cast-type* of `int` results in a conversion to type `int`. See [§§](08-conversions.md#converting-to-integer-type) for details.
A *cast-type* of `float` results in a conversion to type `float`. See [§§](08-conversions.md#converting-to-floating-point-type) for details.
A *cast-type* of `string` results in a conversion to type `string`. See [§§](08-conversions.md#converting-to-string-type)
for details.
Note that *cast-type* cannot be a [generic type parameter](14-generic-types-methods-and-functions.md#type-parameters).
**Examples**
```Hack
(int)(10/3) // results in the int 3 rather than the float 3.333...
```
### Await Operator
**Syntax**
await-expression:
await expression
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
**Constraints**
This operator must be used within an[ asynchronous function](15-functions.md#asynchronous-functions).
*expression* must have a type that implements [`Awaitableinstanceof-expression: unary-expression instanceof-subject instanceof instanceof-type-designator instanceof-subject: expression instanceof-type-designator: qualified-name variable-name**Defined elsewhere** * [*expression*](10-expressions.md#yield-operator) * [*qualified-name*](20-namespaces.md#defining-namespaces) * [*unary-expression*](10-expressions.md#general-4) * [*variable-name*](09-lexical-structure.md#names) **Constraints** The *expression* in *instanceof-subject* must designate a variable. *qualified-name* must be the name of a class or interface type. *variable-name* must name a value having the [`classname` type](05-types.md#the-classname-type). **Semantics** Operator `instanceof` returns `true` if the variable designated by *expression* in *instanceof-subject* is an object having type *qualified-name* or *variable-name*, is an object whose type is derived from type *qualified-name* or *variable-name*, or is an object whose type implements interface *qualified-name* or *variable-name*. Otherwise, it returns `false`. If either *expression* is not an instance, `false` is returned. Note: This operator supersedes the library function [`is_a`](http://www.php.net/is_a), which has been deprecated. **Examples** ```Hack class C1 { … } $c1 = new C1(); class C2 { … } $c2 = new C2(); class D extends C1 { … } $d = new D(); $d instanceof C1 // true $d instanceof C2 // false $d instanceof D // true // ----------------------------------------- interface I1 { … } interface I2 { … } class E1 implements I1, I2 { … } $e1 = new E1(); $e1 instanceof I1 // true ``` ## Multiplicative Operators **Syntax**
multiplicative-expression:
instanceof-expression
multiplicative-expression * instanceof-expression
multiplicative-expression / instanceof-expression
multiplicative-expression % instanceof-expression
**Defined elsewhere**
* [*instanceof-expression*](10-expressions.md#instanceof-operator)
**Constraints**
The operands of the `*` and `/` operators must have arithmetic type.
The operands of the `%` operator must have integer type.
The right-hand operand of operator `/` and operator `%` must not be zero.
**Semantics**
The binary `*` operator produces the product of its operands. If either operand has type
`float`, the other is converted to that type, and the result has type
`float`. Otherwise, both operands have type `int`, in which case, if the
resulting value can be represented in type `int` that is the result type.
Otherwise, the type and value of [the result is implementation-defined](05-types.md#the-integer-type).
Division by zero results in a diagnostic followed by a `bool` result
having value `false`. (The values +/- infinity and NaN cannot be generated
via this operator; instead, use the predefined constants `INF` and `NAN`.)
The binary `/` operator produces the quotient from dividing the left-hand
operand by the right-hand one. If either operand has type `float`, the other is
converted to that type, and the result has type `float`. Otherwise, both
operands have type `int`, in which case, if the mathematical value of the
computation can be preserved using type `int`, that is the result type;
otherwise, the type of the result is `float`.
The binary `%` operator produces the remainder from dividing the left-hand
operand by the right-hand one. The result has type `int`.
These operators associate left-to-right.
**Examples**
```Hack
-10 * 100 → int with value -1000
100 * -3.4e10 → float with value -3400000000000
"123" * "2e+5" → float with value 24600000
100 / 100 → int with value 1
100 / 123 → float with value 0.8130081300813
123 % 100 → int with value 23
```
## Additive Operators
**Syntax**
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
additive-expression . multiplicative-expression
**Defined elsewhere**
* [*multiplicative-expression*](#multiplicative-operators)
**Constraints**
If either operand has array type, the other operand must also have array
type, and the two types must have a subtype relationship.
If the operands of the `*` and `/` operators do not both have array type, they must both have arithmetic type.
**Semantics**
For non-array operands, the binary `+` operator produces the sum of those
operands, while the binary `- `operator produces the difference of its
operands when subtracting the right-hand operand from the left-hand one.
If either operand has type `float`, the other is converted to that type, and
the result has type `float`. Otherwise, both operands have type `int`, in
which case, if the resulting value can be represented in type `int` that
is the result type. Otherwise, the type and value of [the result is implementation-defined](05-types.md#the-integer-type).
If both operands have array type, the binary `+` operator produces a new
array that is the union of the two operands. The result is a copy of the
left-hand array with elements inserted at its end, in order, for each
element in the right-hand array whose key does not already exist in the
left-hand array. Any element in the right-hand array whose key exists in
the left-hand array is ignored. In this context, this operator is not commutative.
The binary `.` operator creates a string that is the concatenation of the
left-hand operand and the right-hand operand, in that order. If either
or both operands have types other than `string`, their values are
converted to type `string`. The result has type `string`.
These operators associate left-to-right.
**Examples**
```Hack
-10 + 100 → int with value 90
100 + -3.4e10 → float with value -33999999900
100 - 123 → int with value 23
-3.4e10 - abc → float with value -34000000000
// -----------------------------------------
array(66) + array(100, 200) → array(66, 200)
array(2 => 'aa') + array(-4 => 'bb', 6 => 'cc') → array(2 => 'aa', -4 => 'bb', 6 => 'cc')
array('red' => 12, 'green' => 7) + array('blue' => 3) → array('red' => 12, 'green' => 7, 'blue' => 3)
// -----------------------------------------
-10 . NAN → string with value "-10NAN"
INF . "2e+5" → string with value "INF2e+5"
true . null → string with value "1"
10 + 5 . 12 . 100 - 50 → int with value 1512050; ((((10 + 5).12).100)-50)
```
## Bitwise Shift Operators
**Syntax**
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
**Defined elsewhere**
* [*additive-expression*](10-expressions.md#additive-operators)
**Constraints**
Each of the operands must have `int` type.
**Semantics**
Given the expression `e1 << e2`, the bits in the value of `e1` are shifted
left by `e2` positions. Bits shifted off the left end are discarded, and
zero bits are shifted on from the right end. Given the expression
`e1 >> e2`, the bits in the value of `e1` are shifted right by
`e2` positions. Bits shifted off the right end are discarded, and the sign
bit is propagated from the left end.
The type of the result is `int`, and the value of the result is that after
the shifting is complete. The values of `e1` and `e2` are unchanged.
If the shift count is negative, the actual shift applied is `n -
(-shift count % n)`, where `n` is the number of bits per `int`. If the
shift count is greater than the number of bits in an `int`, the actual
shift applied is shift count `% n`.
These operators associate left-to-right.
**Examples**
```Hack
1000 >> 2 // 3E8 is shifted right 2 places
-1000 << 2 // FFFFFC18 is shifted left 5 places
123 >> 128 // adjusted shift count = 0
123 << 33 // For a 32-bit int, adjusted shift count = 1; otherwise, 33
```
## Relational Operators
**Syntax**
relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression
**Defined elsewhere**
* [*shift-expression*](10-expressions.md#bitwise-shift-operators)
**Constraints**
If either operand has an enumerated type, the other operand must have the exact same type.
**Semantics**
Operator `<` represents *less-than*, operator `>` represents
*greater-than*, operator `<=` represents *less-than-or-equal-to*, and
operator `>=` represents *greater-than-or-equal-to*.
The type of the result is `bool`.
The operands are processed using the following steps, in order:
1. If the operands both have arithmetic type, the result is the numerical comparison of the two operands after conversion.
2. If both operands are non-numeric strings, the result is the lexical comparison of the two operands. Specifically, the strings are compared byte-by-byte starting with their first byte. If the two bytes compare equal and there are no more bytes in either string, the strings are equal and the comparison ends; otherwise, if this is the final byte in one string, the shorter string compares less-than the longer string and the comparison ends. If the two bytes compare unequal, the string having the lower-valued byte compares less-than the other string, and the comparison ends. If there are more bytes in the strings, the process is repeated for the next pair of bytes.
3. If both operands are numeric strings, the result is the numeric comparison of the two operands after conversion.
4. If both operands have vector-like or map-like array type, if the arrays have different numbers of elements, the one with the fewer is considered less-than the other one—regardless of the keys and values in each—, and the comparison ends. For arrays having the same numbers of elements, if the next key in the left-hand operand exists in the right-hand operand, the corresponding values are compared. If they are unequal, the array containing the lesser value is considered less-than the other one, and the comparison ends; otherwise, the process is repeated with the next element. If the next key in the left-hand operand does not exist in the right-hand operand, the arrays cannot be compared and `false` is returned. For array comparison, the order of insertion of the elements into those arrays is irrelevant.
5. If the operands have the same object type, the result is decided by comparing the lexically first-declared instance property in each object. If those properties have object type, the comparison is applied recursively.
Regarding operands having the same enumeration type, for an `int`-based enumeration the enumeration is compared using its value directly as an `int`. For a `string`-based enumeration, the enumeration is compared using its value directly as a `string`. (**The validity of allowing these operators to have an enumerated type as an operand is questionable; avoid such usage lest support for it disappears.**)
These operators associate left-to-right.
**Examples**
```Hack
"" < "ab" → result has value true
"a" > "A" → result has value true
"a0" < "ab" → result has value true
"aA <= "abc" → result has value true
// -----------------------------------------
10 <= 0 → result has value false
'123' <= '4') → false; is doing a numeric comparison
'X123' <= 'X4' → true; is doing a string comparison
// -----------------------------------------
[100] < [10,20,30] → result has value true (LHS array is shorter)
```
**Notes**
Ideally, one might expect some constraints on the combination of operand types. However, for historical reasons, other behaviors from PHP have been retained, as documented.
## Equality Operators
**Syntax**
equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
equality-expression === relational-expression
equality-expression !== relational-expression
**Defined elsewhere**
* [*relational-expression*](10-expressions.md#relational-operators)
**Semantics**
Operator `==` represents *value-equality*, operator `!=` represents *value-inequality*, operator `===` represents
*same-type-and-value-equality*, and operator `!==` represents
*not-same-type-and-value-equality*. However, when comparing two objects,
operator `===` represents *identity* and operator `!==` represents
*non-identity*. Specifically, in this context, these operators check to
see if the two operands are the exact same object, not two different
objects of the same type and value.
The type of the result is `bool`.
The operands are processed using the following steps, in order:
1. For operators `==`, `!=`, and `<>`, if either operand has the value
`null`, then if the other operand has type string, the `null` is
converted to the empty string (""); otherwise, the `null` is converted
to type bool.
2. If both operands are non-numeric strings or one is a numeric string
and the other a leading-numeric string, the result is the lexical
comparison of the two operands. Specifically, the strings are
compared byte-by-byte starting with their first byte. If the two
bytes compare equal and there are no more bytes in either string,
the strings are equal and the comparison ends; otherwise, if this is
the final byte in one string, the shorter string compares less-than
the longer string and the comparison ends. If the two bytes compare
unequal, the string having the lower-valued byte compares less-than
the other string, and the comparison ends. If there are more bytes
in the strings, the process is repeated for the next pair of bytes.
3. If either operand has type bool, for operators `==` and `!=`, the
other operand is converted to that type. The result is the logical
comparison of the two operands after any conversion, where `false` is
defined to be less than `true`.
4. If the operands both have arithmetic type, string type, or are
resources, for operators `==` and `!=`, they are converted to the
corresponding arithmetic type [§§](08-conversions.md#converting-to-integer-type) and [§§](08-conversions.md#converting-to-floating-point-type)). The result is the
numerical comparison of the two operands after any conversion.
5. If both operands have array type, for operators `==` and `!=`,
the arrays are equal if they have the same set of key/value pairs and the corresponding values have the same type,
after element type conversion, without regard to the order of
insertion of their elements. For operators `===` and `!==` the arrays
are equal if they have the same set of key/value pairs, the
corresponding values have the same type, and the order of insertion
of their elements are the same.
6. If only one operand has object type, the two operands are never
equal.
7. If only one operand has array type, the two operands are never
equal.
8. If the operands have different object types, the two operands are
never equal except that a `Vector` and an `ImmVector` having the same member type and value set can be equal, as can a `Map` and an `ImmMap`, and a `Set` and an `ImmSet`.
9. If the operands have the same object type, the two operands are
equal if the instance properties in each object have the same
values. Otherwise, the objects are unequal. The instance properties
are compared, one at a time, in the lexical order of their
declaration. For properties that have object type, the comparison is
applied recursively.
These operators associate left-to-right.
**Examples**
```Hack
"a" <> "aa" // result has value true
// -----------------------------------------
null == 0 // result has value true
null === 0 // result has value false
true != 100 // result has value false
true !== 100 // result has value true
// -----------------------------------------
"10" != 10 // result has value false
"10" !== 10 // result has value true
// -----------------------------------------
[10,20] == [10,20.0] // result has value true
[10,20] === [10,20.0] // result has value false
["red"=>0,"green"=>0] === ["red"=>0,"green"=>0] // result has value true
["red"=>0,"green"=>0] === ["green"=>0,"red"=>0] // result has value false
```
**Notes**
Ideally, one might expect some constraints on the combination of operand types. However, for historical reasons, other behaviors from PHP have been retained, as documented.
# # Bitwise AND Operator
**Syntax**
bitwise-AND-expression:
equality-expression
bit-wise-AND-expression & equality-expression
**Defined elsewhere**
* [*equality-expression*](10-expressions.md#equality-operators)
**Constraints**
Each of the operands must have `int` type.
**Semantics**
The result of this operator is the bitwise-AND of the two operands, and
the type of that result is `int`.
This operator associates left-to-right.
**Examples**
```Hack
0b101111 & 0b101 // 0b101
$lLetter = 0x73; // letter 's'
$uLetter = $lLetter & ~0x20; // clear the 6th bit to make letter 'S'
```
## Bitwise Exclusive OR Operator
**Syntax**
bitwise-exc-OR-expression:
bitwise-AND-expression
bitwise-exc-OR-expression ^ bitwise-AND-expression
**Defined elsewhere**
* [*bitwise-AND-expression*](10-expressions.md#bitwise-and-operator)
**Constraints**
Each of the operands must have `int` type.
**Semantics**
The result of this operator is the bitwise exclusive-OR of the two
operands, and the type of that result is `int`.
This operator associates left-to-right.
**Examples**
```Hack
0b101111 | 0b101 // 0b101010
$v1 = 1234; $v2 = -987; // swap two integers having different values
$v1 = $v1 ^ $v2;
$v2 = $v1 ^ $v2;
$v1 = $v1 ^ $v2; // $v1 is now -987, and $v2 is now 1234
```
## Bitwise Inclusive OR Operator
**Syntax**
bitwise-inc-OR-expression:
bitwise-exc-OR-expression
bitwise-inc-OR-expression | bitwise-exc-OR-expression
**Defined elsewhere**
* [*bitwise-exc-OR-expression*](10-expressions.md#bitwise-exclusive-or-operator)
**Constraints**
Each of the operands must have `int` type.
**Semantics**
The result of this operator is the bitwise inclusive-OR of the two
operands, and the type of that result is `int`.
This operator associates left-to-right.
**Examples**
```Hack
0b101111 | 0b101 // 0b101111
$uLetter = 0x41; // letter 'A'
$lLetter = $upCaseLetter | 0x20; // set the 6th bit to make letter 'a'
```
## Logical AND Operator
**Syntax**
logical-AND-expression:
bitwise-inc-OR-expression
logical-AND-expression && bitwise-inc-OR-expression
**Defined elsewhere**
* [*bitwise-inc-OR-expression*](10-expressions.md#bitwise-inclusive-or-operator)
**Constraints**
Each of the operands must have scalar type.
**Semantics**
If either operand does not have type bool, its value is first converted
to that type. An `int`-based enumeration with value zero is converted to `false`, while a non-zero value is converted to `true`. Likewise, a `string`-based enumeration with value empty string is converted to `false`, while a non-empty value is converted to `true`. (**The validity of allowing this operator to have an enumerated type operand is questionable; avoid such usage lest support for it disappears.**)
Given the expression `e1 && e2, e1` is evaluated first. If `e1` is `false`, `e2` is not evaluated, and the result has type `bool`, value `false`. Otherwise, `e2` is evaluated. If `e2` is `false`, the result has type bool, value `false`; otherwise, it has type `bool`, value `true`. There is a sequence point after the evaluation of `e1`.
This operator associates left-to-right.
**Examples**
```Hack
if ($month > 1 && $month <= 12) ...
```
## Logical Inclusive OR Operator
**Syntax**
logical-inc-OR-expression:
logical-AND-expression
logical-inc-OR-expression || logical-AND-expression
**Defined elsewhere**
* [*logical-AND-expression*](10-expressions.md#logical-and-operator)
**Constraints**
Each of the operands must have scalar type.
**Semantics**
If either operand does not have type bool, its value is first converted
to that type. An `int`-based enumeration with value zero is converted to `false`, while a non-zero value is converted to `true`. Likewise, a `string`-based enumeration with value empty string is converted to `false`, while a non-empty value is converted to `true`. (**The validity of allowing this operator to have an enumerated type operand is questionable; avoid such usage lest support for it disappears.**)
Given the expression `e1 || e2`, `e1` is evaluated first. If `e1` is true, `e2` is not evaluated, and the result has type `bool`, value `true`. Otherwise, `e2` is evaluated. If `e2` is `true`, the result has type `bool`, value `true`; otherwise, it has type `bool`, value `false`. There is a sequence point after the evaluation of `e1`.
This operator associates left-to-right.
**Examples**
```Hack
if ($month < 1 || $month > 12) ...
```
## Conditional Operator
**Syntax**
conditional-expression:
logical-inc-OR-expression
logical-inc-OR-expression ? expressionopt : conditional-expression
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
* [*logical-inc-OR-expression*](10-expressions.md#logical-inclusive-or-operator)
**Semantics**
Given the expression `e1 ? e2 : e3`, if `e1` is `true`, then and only then is `e2` evaluated, and the result and its type become the result and type of
the whole expression. Otherwise, then and only then is `e3` evaluated, and
the result and its type become the result and type of the whole
expression. There is a sequence point after the evaluation of `e1`. If `e2`
is omitted, the result and type of the whole expression is the value and
type of `e1` when it was tested.
Regarding a left-most operand that is an enumeration, an `int`-based enumeration with value zero is converted to `false`, while a non-zero value is converted to `true`. Likewise, a string-based enumeration with value empty string is converted to `false`, while a non-empty value is converted to `true`. (**The validity of allowing this operator to have an enumerated type as its first operand is questionable; avoid such usage lest support for it disappears.**)
This operator associates left-to-right.
**Examples**
```Hack
for ($i = -5; $i <= 5; ++$i)
echo "$i is ".(($i & 1 == true) ? "odd\n" : "even\n");
// -----------------------------------------
$a = 10 ? : "Hello"; // result is int with value 10
$a = 0 ? : "Hello"; // result is string with value "Hello"
$i = PHP_INT_MAX;
$a = $i++ ? : "red"; // result is int with value 2147483647 (on a 32-bit
// system) even though $i is now the float 2147483648.0
// -----------------------------------------
$i++ ? f($i) : f(++$i); // the sequence point makes this well-defined
// -----------------------------------------
function factorial(int $int): int
{
return ($int > 1) ? $int * factorial($int - 1) : $int;
}
```
## Coalesce Operator
**Syntax**
coalesce-expression:
logical-inc-OR-expression ?? expression
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
* [*logical-inc-OR-expression*](#logical-inclusive-or-operator)
**Semantics**
Given the expression `e1 ?? e2`, if `e1` is set and not `null`, then the result is `e1`. Otherwise, then and only then is `e2`
evaluated, and the result becomes the result of the whole expression. There is a sequence point after the evaluation of `e1`.
This operator associates right-to-left.
**Examples**
```PHP
function foo(): void {
echo "executed!", PHP_EOL;
}
function main(): void {
$arr = ["foo" => "bar", "qux" => null];
$obj = (object)$arr;
$a = $arr["foo"] ?? "bang"; // "bar" as $arr["foo"] is set and not null
$a = $arr["qux"] ?? "bang"; // "bang" as $arr["qux"] is null
$a = $arr["bing"] ?? "bang"; // "bang" as $arr["bing"] is not set
$a = $obj->foo ?? "bang"; // "bar" as $obj->foo is set and not null
$a = $obj->qux ?? "bang"; // "bang" as $obj->qux is null
$a = $obj->bing ?? "bang"; // "bang" as $obj->bing is not set
$a = null ?? $arr["bing"] ?? 2; // 2 as null is null, and $arr["bing"] is not set
var_dump(true ?? foo()); // outputs bool(true), "executed!" does not appear as it short-circuits
}
```
## Pipe Operator
**Syntax**
piped-expression: coalesce-expression piped-expression |> coalesce-expression*coalesce-expression* is defined in [§§](10-expressions.md#coalesce-operator). **Constraints** *piped-expression* cannot be used as the right-hand operand of an assignment operator. *coalesce-expression* must contain at least one occurrence of the pipe variable `$$`. **Semantics** *piped-expression* is evaluated with the result being stored in the pipe variable `$$`. There is a sequence point after the evaluation of *piped-expression*. Then *coalesce-expression* is evaluated, and its type and value become the type and value of the result. This operator associates left-to-right. **Examples** ```PHP class Widget { … } function pipe_operator_example(array
lambda-expression: piped-expression asyncopt lambda-function-signature ==> lambda-body lambda-function-signature: variable-name ( anonymous-function-parameter-listopt ) anonymous-function-returnopt lambda-body: expression compound-statement**Defined elsewhere** * [*anonymous-function-parameter-list*](10-expressions.md#anonymous-function-creation) * [*anonymous-function-return*](10-expressions.md#anonymous-function-creation) * [*coalesce-expression*](10-expressions.md#coalesce-operator) * [*compound-statement*](11-statements.md#compound-statements) * [*conditional-expression*](10-expressions.md#conditional-operator) * [*expression*](10-expressions.md#yield-operator) * [*piped-expression*](10-expressions.md#pipe-operator) * [*variable-name*](09-lexical-structure.md#names) **Constraints** Each variable-name in an *anonymous-function-parameter-list* must be distinct. If any *anonymous-function-parameter-declaration* has a *default-argument-specifier*, then all subsequent *anonymous-function-parameter-declarations* in the same *anonymous-function-parameter-declaration-list* must also have a *default-argument-specifier*. If the *type-specifier* in *anonymous-function-return* is `void`, the *compound-statement* must not contain any [`return` statements](11-statements.md#the-return-statement) having an *expression*. Otherwise, if that *type-specifier* is not omitted, the *expression* in *lambda-body*, or all `return` statements in *compound-statement* must contain an *expression* whose type is a subtype of the type indicated by the return type's *type-specifier*. If `async` is present, *return-type* must be a type that implements [`Awaitable
assignment-expression:
lambda-expression
simple-assignment-expression
compound-assignment-expression
**Defined elsewhere**
* [*compound-assignment-expression*](10-expressions.md#compound-assignment)
* [*lambda-expression*](10-expressions.md#lambda-expressions)
* [*simple-assignment-expression*](10-expressions.md#simple-assignment)
**Constraints**
The left-hand operand of an assignment operator must be a modifiable
lvalue.
**Semantics**
These operators associate right-to-left.
### Simple Assignment
**Syntax**
simple-assignment-expression:
unary-expression = assignment-expression
**Defined elsewhere**
* [*assignment-expression*](10-expressions.md#general-5)
* [*unary-expression*](10-expressions.md#general-4)
**Constraints**
If the location designated by the left-hand operand is a string element,
the key must not be a negative-valued `int`, and the right-hand operand
must have type `string`.
If *unary-expression* is a [*subscript-expression*](10-expressions.md#subscript-operator) whose *postfix-expression* designates a vector-like array and whose *expression* is present, if *expression* designates a non-existent element, the behavior is unspecified.
If *unary-expression* is a *subscript-expression* whose *postfix-expression* designates a `Map` and whose *expression* is omitted, *assignment-expression* must designate a `Pair`.
**Semantics**
If *assignment-expression* designates an expression having value type,
see [§§](04-basic-concepts.md#value-assignment-of-scalar-types-to-a-local-variable). If *assignment-expression*
designates an expression having a handle, see [§§](04-basic-concepts.md#byref-assignment-for-scalar-types-with-local-variables). If
*assignment-expression* designates an expression having array type, see
[§§](04-basic-concepts.md#value-assignment-of-array-types-to-local-variables). If *assignment-expression* designates an expression having a shape type, it is treated as if it had array type.
The type and value of the result is the type and value of the left-hand
operand after the store (if any [see below]) has taken place. The result
is not an lvalue.
If the location designated by the left-hand operand is a non-existent
array element, a new element is inserted with the designated key and
with a value being that of the right-hand operand.
If the location designated by the left-hand operand is a string element,
then if the key is a negative-valued `int`, there is no side effect.
Otherwise, if the key is a non-negative-valued `int`, the left-most single
character from the right-hand operand is stored at the designated
location; all other characters in the right-hand operand string are
ignored. If the designated location is beyond the end of the
destination string, that string is extended to the new length with
spaces (U+0020) added as padding beyond the old end and before the newly
added character. If the right-hand operand is an empty string, the null
character \\0 (U+0000) is stored.
**Examples**
```Hack
$a = $b = 10 // equivalent to $a = ($b = 10)
$v = array(10, 20, 30);
$v[-10] = 19; // insert a new element with int key -10
$s = "red";
$s[1] = "X"; // OK; "e" -> "X"
$s[-5] = "Y"; // warning; string unchanged
$s[5] = "Z"; // extends string with "Z", padding with spaces in [3]-[5]
$s = "red";
$s[0] = "DEF"; // "r" -> "D"; only 1 char changed; "EF" ignored
$s[0] = ""; // "D" -> "\0"
$s["zz"] = "Q"; // warning; defaults to [0], and "Q" is stored there
// -----------------------------------------
class C { … }
$a = new C(); // make $a point to the allocated object
```
### Compound Assignment
**Syntax**
compound-assignment-expression:
unary-expression compound-assignment-operator assignment-expression
compound-assignment-operator: one of
**= *= /= %= += -= .= <<= >>= &= ^= |=
**Defined elsewhere**
* [*assignment-expression*](10-expressions.md#general-5)
* [*unary-expression*](10-expressions.md#general-4)
**Constraints**
Any constraints that apply to the corresponding postfix or binary
operator apply to the compound-assignment form as well.
**Semantics**
The expression `e1 op= e2` is equivalent to `e1 = e1 op (e2)`, except
that `e1` is evaluated once only.
**Examples**
```Hack
$v = 10;
$v += 20; // $v = 30
$v -= 5; // $v = 25
$v .= 123.45 // $v = "25123.45"
$a = [100, 200, 300];
$i = 1;
$a[$i++] += 50; // $a[1] = 250, $i → 2
```
## `yield` Operator
**Syntax**
expression:
assignment-expression
yield array-element-initializer
**Defined elsewhere**
* [*array-element-initializer*](#array-creation-operator)
* [*assignment-expression*](10-expressions.md#general-5)
**Constraints**
`yield` must not be used inside an [async function, method, or closure](15-functions.md#asynchronous-functions).
**Semantics**
Any function containing a yield operator is a *generator function*.
A generator function generates a collection of zero or more key/value
pairs where each pair represents the next in some series. For example, a
generator might *yield* random numbers or the series of Fibonacci
numbers. When a generator function is called explicitly, it returns an
object of type `Generator` (see below and [§§](16-classes.md#class-generator)), which implements the interface
[`Iterator`](15-interfaces.md#interface-iterator). As such, this allows that object to be iterated over
using the [`foreach` statement](11-statements.md#the-foreach-statement). During each iteration, the Engine
calls the generator function implicitly to get the next key/value pair.
Then the Engine saves the state of the generator for subsequent
key/value pair requests.
This operator produces the result `null` unless the method
[`Generator->send`](16-classes.md#class-generator) was called to provide a result value. This
operator has the side effect of generating the next value in the
collection.
Before being used, an *element-key* must have, or be converted to, type
`int` or `string`. Keys with `float` or `bool` values, or strings whose contents
match exactly the pattern of [*decimal-literal*](09-lexical-structure.md#integer-literals), are
[converted to `int`](08-conversions.md#converting-to-integer-type). Values of all other key types are [converted to `string`](08-conversions.md#converting-to-string-type).
If *element-key* is omitted from an *array-element-initializer*, an
element key of type `int` is associated with the corresponding
*element-value*. The key associated is one more than the previously
assigned int key for this collection. However, if this is the first
element in this collection with an `int` key, key zero is used. If
*element-key* is provided, it is associated with the corresponding
*element-value*. The resulting key/value pair is made available by
`yield`.
If *array-element-initializer* is omitted, default int-key assignment is
used and each value is `null`.
A generator function's return type is `Generator
constant-expression:
array-creation-expression
collection-literal
tuple-literal
shape-literal
const-expression
const-expression:
expression
**Defined elsewhere**
* [*array-creation-expression*](10-expressions.md#array-creation-operator)
* [*collection-literal*](10-expressions.md#collection-literals)
* [*expression*](10-expressions.md#yield-operator)
* [*shape-literal*](10-expressions.md#shape-literals)
* [*tuple-literal*](10-expressions.md#tuple-literals)
**Constraints:**
All of the *element-key* and *element-value* *expression*s in
[*array-creation-expression*](10-expressions.md#array-creation-operator) must be [*literals*](09-lexical-structure.md#general-2), or *tuple-literals* and/or *shape-literals* containing only *literals*.
All of the *expression*s in a *collection-literal* must be *literals*.
All of the *expression*s in *tuple-literal* must be *literals*.
All of the *expression*s in *shape-literal* must be *literals*.
*expression* must have a scalar type, and be a literal or the name of an
existing [c-constant](06-constants.md#general) that is currently in scope.
**Semantics:**
A *const-expression* is the value of a c-constant. A *const-expression*
is required in several contexts, such as in initializer values in a
[*const-declaration*](16-classes.md#constants) and default initial values in a [function
definition](15-functions.md#function-definitions).
================================================
FILE: spec/11-statements.md
================================================
# Statements
## General
**Syntax**
statement:
function-static-declaration
compound-statement
labeled-statement
expression-statement
selection-statement
iteration-statement
jump-statement
try-statement
**Defined elsewhere**
* [*compound-statement*](#compound-statements)
* [*expression-statement*](#expression-statements)
* [*function-static-declaration*](07-variables.md#function-statics)
* [*iteration-statement*](#general-2)
* [*jump-statement*](#general-3)
* [*labeled-statement*](#labeled-statements)
* [*selection-statement*](#general-1)
* [*try-statement*](11-statements.md#the-try-statement)
## Compound Statements
**Syntax**
compound-statement:
{ statement-listopt }
statement-list:
statement
statement-list statement
**Defined elsewhere**
* [*statement*](#general)
**Semantics**
A *compound statement* allows a group of zero or more statements to be
treated syntactically as a single statement. A compound statement is
often referred to as a *block*.
**Examples**
```Hack
if (condition)
{ // braces are needed as the true path has more than one statement
// statement-1
// statement-2
}
else
{ // braces are optional as the false path has only one statement
// statement-3
}
// -----------------------------------------
while (condition)
{ // the empty block is equivalent to a null statement
}
```
## Labeled Statements
**Syntax**
labeled-statement:
case-label
default-label
case-label:
case expression : statement
default-label:
default : statement
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
* [*statement*](#general)
**Constraints**
*case-label* and *default-label* must only occur inside a [`switch` statement](#the-switch-statement).
**Semantics**
See the `switch` statement.
## Expression Statements
**Syntax**
expression-statement:
expressionopt ;
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
**Semantics**
If present, *expression* is evaluated for its side effects, if any, and
any resulting value is discarded. If *expression* is omitted, the
statement is a *null statement*, which has no effect on execution.
**Examples**
```Hack
$i = 10; // $i is assigned the value 10; result (10) is discarded
++$i; // $i is incremented; result (11) is discarded
$i++; // $i is incremented; result (11) is discarded
DoIt(); // function DoIt is called; result (return value) is discarded
// -----------------------------------------
$i; // no side effects, result is discarded. Vacuous but permitted
123; // likewise for this one and the two statements following
34.5 * 12.6 + 11.987;
true;
```
## Selection Statements
### General
**Syntax**
selection-statement:
if-statement
switch-statement
**Defined elsewhere**
* [*if-statement*](#the-if-statement)
* [*switch-statement*](#the-switch-statement)
**Semantics**
Based on the value of a controlling expression, a selection statement
selects among a set of statements.
### The `if` Statement
**Syntax**
if-statement:
if ( expression ) statement elseif-clauses-opt else-clause-opt
elseif-clauses:
elseif-clause
elseif-clauses elseif-clause
elseif-clause:
elseif ( expression ) statement
else-clause:
else statement
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
* [*statement*](#general)
**Constraints**
The controlling expression *expression* must have type `bool` or be
implicitly convertible to that type.
**Semantics**
The two forms of the `if` statement are equivalent; they simply provide
alternate styles.
If *expression* tests `true`, the *statement* that follows immediately is
executed. Otherwise, if an `elseif` clause is present the *statement*
immediately following the `elseif` is executed. Otherwise, any other
`elseif` *expression*s are evaluated. If none of those tests `true`, if an
`else` clause is present the *statement* immediately following the `else` is
executed.
An `else` clause is associated with the lexically nearest preceding `if` or
`elseif` that is permitted by the syntax.
**Examples**
```Hack
if ($count > 0) {
…
} else {
…
}
// -----------------------------------------
if (1)
…
if (0)
…
else // this else does NOT go with the outer if
…
if (1) {
…
if (0)
…
} else // this else does go with the outer if
…
```
### The `switch` Statement
**Syntax**
switch-statement:
switch ( expression ) compound-statement
**Defined elsewhere**
* [*compound-statement*](#compound-statements)
* [*expression*](10-expressions.md#yield-operator)
**Constraints**
The controlling expression *expression* must have scalar type.
There must be at most one default label.
Each label expression's type must be a subtype of the switch *expression* type.
The compound statement may be empty; if it is not, then the first statement in
it must be a labeled statement.
**Semantics**
Based on the value of its *expression*, a `switch` statement transfers
control to a [case label](#labeled-statements); to a [default label](#labeled-statements), if one
exists; or to the statement immediately following the end of the `switch`
statement. A case or default label is only reachable directly within its
closest enclosing `switch` statement.
On entry to the `switch` statement, the controlling expression is
evaluated and then compared with the value of the case-label-expression
values, in lexical order. If one matches, control transfers to the
statement following the corresponding case label. If there is no match,
then if there is a default label, control transfers to the statement
following that; otherwise, control transfers to the statement
immediately following the end of the `switch` statement. If a `switch`
contains more than one case label whose values compare equal to the
controlling expression, the first in lexical order is considered the
match.
An arbitrary number of statements can be associated with any case or
default label. In the absence of a [`break` statement](11-statements.md#the-break-statement) at the end
of a set of such statements, control drops through into any following
case or default label. Thus, if all cases and the default end in break
and there are no duplicate-valued case labels, the order of case and
default labels is insignificant.
In no break *statement* is seen for a case or default before a subsequent case label, default label, or the switch-terminating `}` is encountered, an implementation might issue a warning. However, such a warning can be suppressed by placing a source line containing the special comment [`// FALLTHROUGH`](09-lexical-structure.md#comments), at the end of that case or default statement group.
Case-label values can be runtime expressions, and the types of sibling
case-label values need not be the same.
Switches may be nested, in which case, each `switch` has its own set of
`switch` clauses.
**Examples**
```Hack
$v = 10;
switch ($v) {
default:
echo "default case: \$v is $v\n";
break; // break ends "group" of default statements
case 20:
echo "case 20\n";
break; // break ends "group" of case 20 statements
case 10:
echo "case 10\n"; // no break, so control drops into next label's "group"
// FALLTHROUGH
case 30:
echo "case 30\n"; // no break, but then none is really needed either
}
// -----------------------------------------
$v = 30;
switch ($v) {
case 30.0: // <===== this case matches with 30
echo "case 30.0\n";
break;
default:
echo "default case: \$v is $v\n";
break;
case 30: // <===== rather than this case matching with 30
echo "case 30\n";
break;
}
// -----------------------------------------
enum ControlStatus: int {
Stopped = 0;
Stopping = 1;
Starting = 2;
Started = 3;
}
…
switch ($p1) {
case ControlStatus::Stopped:
echo "Stopped: $p1\n";
break;
…
case ControlStatus::Started:
echo "Started: $p1\n";
break;
}
```
## Iteration Statements
### General
**Syntax**
iteration-statement:
while-statement
do-statement
for-statement
foreach-statement
**Defined elsewhere**
* [*do-statement*](#the-do-statement)
* [*for-statement*](#the-for-statement)
* [*foreach-statement*§](#the-foreach-statement)
* [*while-statement*](#the-while-statement)
### The `while` Statement
**Syntax**
while-statement:
while ( expression ) statement
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
* [*statement*](#general)
**Constraints**
The controlling expression *expression* must have type `bool` or be
implicitly convertible to that type.
**Semantics**
If *expression* tests `true`, the *statement* that follows immediately is
executed, and the process is repeated. If *expression* tests `false`,
control transfers to the point immediately following the end of the
`while` statement. The loop body, *statement*, is executed zero or more
times.
**Examples**
```Hack
$i = 1;
while ($i <= 10) {
echo "$i\t".($i * $i)."\n"; // output a table of squares
++$i;
}
// -----------------------------------------
while (true) {
…
if ($done)
break; // break out of the while loop
…
}
```
### The `do` Statement
**Syntax**
do-statement:
do statement while ( expression ) ;
**Defined elsewhere**
* [*statement*](#general)
* [*expresion*](10-expressions.md#yield-operator)
(Note: There is no `:/enddo` alternate syntax.)
**Constraints**
The controlling expression *expression* must have type `bool` or be
implicitly convertible to that type.
**Semantics**
First, *statement* is executed and then *expression* is tested. If its
value is `true`, the process is repeated. If *expression* tests `false`,
control transfers to the point immediately following the end of the `do`
statement. The loop body, *statement*, is executed one or more times.
**Examples**
```Hack
$i = 1;
do {
echo "$i\t".($i * $i)."\n"; // output a table of squares
++$i;
}
while ($i <= 10);
```
### The `for` Statement
**Syntax**
for-statement:
for ( for-initializeropt ; for-controlopt ; for-end-of-loopopt ) statement
for-initializer:
for-expression-group
for-control:
for-expression-group
for-end-of-loop:
for-expression-group
for-expression-group:
expression
for-expression-group , expression
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
* [*statement*](#general)
Note: Unlike C/C++, Hack does not support a comma operator, per se.
However, the syntax for the `for` statement has been extended from that of
C/C++ to achieve the same results in this context.
**Constraints**
The controlling expression—the right-most *expression* in
*for-control*—must have type `bool` or be implicitly convertible to that
type.
**Semantics**
The group of expressions in *for-initializer* is evaluated once,
left-to-right, for their side effects. Then the group of expressions in
*for-control* is evaluated left-to-right (with all but the right-most
one for their side effects only), with the right-most expression's value
being tested. If that tests `true`, *statement* is executed, and the group
of expressions in *for-end-of-loop* is evaluated left-to-right, for
their side effects only. Then the process is repeated starting with
*for-control*. If the right-most expression in *for-control* tests
`false`, control transfers to the point immediately following the end of
the `for` statement. The loop body, *statement*, is executed zero or more
times.
If *for-initializer* is omitted, no action is taken at the start of the
loop processing. If *for-control* is omitted, this is treated as if
*for-control* was an expression with the value `true`. If
*for-end-of-loop* is omitted, no action is taken at the end of each
iteration.
**Examples**
```Hack
for ($i = 1; $i <= 10; ++$i) {
echo "$i\t".($i * $i)."\n"; // output a table of squares
}
// -----------------------------------------
// omit 1st and 3rd expressions
$i = 1;
for (; $i <= 10;) {
echo "$i\t".($i * $i)."\n"; // output a table of squares
++$i;
}
// -----------------------------------------
// omit all 3 expressions
$i = 1;
for (;;) {
if ($i > 10)
break;
echo "$i\t".($i * $i)."\n"; // output a table of squares
++$i;
}
// -----------------------------------------
// use groups of expressions
for ($a = 100, $i = 1; ++$i, $i <= 10; ++$i, $a -= 10) {
echo "$i\t$a\n";
}
```
### The `foreach` Statement
**Syntax**
foreach-statement:
foreach ( foreach-collection-name as foreach-keyopt foreach-value ) statement
foreach ( foreach-collection-name await as foreach-keyopt foreach-value ) statement
foreach-collection-name:
expression
foreach-key:
expression =>
foreach-value:
expression
list-intrinsic
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
* [*list-intrinsic*](10-expressions.md#list)
* [*statement*](#general)
**Constraints**
The variable designated by *foreach-collection-name* must be a
collection.
Each *expression* must designate a variable name.
For the “await as” form, the type of *foreach-collection-name* must implement interface [`AsyncIterator`](17-interfaces.md#interface-AsyncIterator) or interface [`AsyncKeyedIterator`](17-interfaces.md#interface-AsyncKeyedIterator).
**Semantics**
The *foreach* statement iterates over the set of elements in the
collection designated by *foreach-collection-name*, starting at the
beginning, executing *statement* each iteration. On each iteration, the value of the current element is assigned to the
corresponding variable designated by *foreach-value*, provided *foreach-value*’s *expression* is not ([`$_`](§09-lexical-structure.md#names); otherwise, the value of the current element is ignored. The loop body, *statement*, is executed zero or
more times.
If *foreach-key* is present and its *expression* is `$_`, the current element's key value is ignored. If *foreach-key* is present and *expression* is not `$_`, the variable designated by its *expression*
is assigned the current element's key value.
In the *list-intrinsic* case, a value that is an array is split into
individual elements.
**Examples**
```Hack
$colors = array("red", "white", "blue");
foreach ($colors as $color) {
…
};
// -----------------------------------------
foreach ($colors as $key => $color) {
…
}
// -----------------------------------------
// Modify the local copy of an element's value
foreach ($colors as $color) {
$color = "black";
}
// -----------------------------------------
$a = array('a' => 10, 'f' => 30);
foreach ($a as $key => $_) { // 10 and 30 are ignored
…
}
// -----------------------------------------
async function countdown1(int $start): AsyncIterator
jump-statement:
continue-statement
break-statement
return-statement
throw-statement
**Defined elsewhere**
* [*break-statement*](#the-break-statement)
* [*continue-statement*](#the-continue-statement)
* [*return-statement*](#the-return-statement)
* [*throw-statement*](#the-throw-statement)
### The `continue` Statement
**Syntax**
continue-statement:
continue ;
**Constraints**
A `continue` statement must not attempt to break out of a [finally-block](#the-try-statement).
**Semantics**
A `continue` statement terminates the execution of the innermost enclosing
[iteration](#iteration-statements) or [`switch`](#the-switch-statement) statement.
A `continue` statement may break out of a construct that is fully
contained within a finally-block.
**Examples**
```Hack
for ($i = 1; $i <= 5; ++$i) {
if (($i % 2) == 0)
continue;
echo "$i is odd\n";
}
```
### The `break` Statement
**Syntax**
break-statement:
break ;
**Constraints**
A `break` statement must not attempt to break out of a [finally-block](#the-try-statement).
**Semantics**
A `break` statement terminates the execution of one or more enclosing
[iteration](#iteration-statements) or [`switch`](#the-switch-statement) statements.
A `break` statement may break out of a construct that is fully contained
within a finally-block.
**Examples**
```Hack
$i = 1;
for (;;) {
if ($i > 10)
break;
…
++$i;
}
```
### The `return` Statement
**Syntax**
return-statement:
return expressionopt ;
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
**Constraints**
The *expression* in a *return-statement* in a [generator function](10-expressions.md#yield-operator) must be the literal `null`.
A `return` statement must not occur in a [finally-block](11-statements.md#the-try-statement) or in the *compound-statement* of a *function-definition* for a function with [*return-type* `noreturn`](15-functions.md#function-definitions).
For a non-async function, the type of *expression* (or any implicitly returned `null`) must be assignment-compatible with the return type of the [enclosing function](15-functions.md#function-definitions). For an async function, the type of *expression* must be a subtype of the parameter type of the `Awaitable` *return-type* for the enclosing function. However, if `Awaitable`’s parameter type is `void`, *expression* must be omitted.
**Semantics**
A `return` statement from within a function terminates the execution of that function normally. If *expression* is omitted, for a non-async function, no value is returned. For a sync function, an object of type `Awaitable
throw-statement:
throw expression ;
**Defined elsewhere**
* [*expression*](10-expressions.md#yield-operator)
**Constraints**
The type of *expression* must be [[\Exception](19-exception-handling.md#class-exception) or a subclass of that
class.
*expression* must be such that an alias to it can be created.
**Semantics**
A `throw` statement throws an exception immediately and unconditionally.
Control never reaches the statement immediately following the throw. See
[§§](19-exception-handling.md#general) and [§§](#the-try-statement) for more details of throwing and catching exceptions,
and how uncaught exceptions are dealt with.
Rather than handle an exception, a catch-block may (re-)throw the same
exception that it caught, or it can throw an exception of a different
type.
**Examples**
```Hack
throw new Exception;
throw new Exception("Some message", 123);
class MyException extends Exception { ... }
throw new MyException;
```
## The `try` Statement
**Syntax**
try-statement:
try compound-statement catch-clauses
try compound-statement finally-clause
try compound-statement catch-clauses finally-clause
catch-clauses:
catch-clause
catch-clauses catch-clause
catch-clause:
catch ( type-specifier variable-name ) compound-statement
finally-clause:
finally compound-statement
**Defined elsewhere**
* [*compound-statement*](#compound-statements)
* [*type-specifier*](05-types.md#general).
* [*variable-name*](09-lexical-structure.md#names)
**Constraints**
In a *catch-clause* the type referred to by the *type-specifier*
must be [`\Exception`](19-exception-handling.md#class-exception) or a type derived from
that class.
**Semantics**
In a *catch-clause*, the *variable-name* designates an *exception variable*
passed in by value. This variable corresponds to a local variable with a
scope that extends over the catch-block. During execution of the
catch-block, the exception variable represents the exception currently
being handled.
Once an exception is thrown, the Engine searches for the nearest
catch-block that can handle the exception. The process begins at the
current function level with a search for a try-block that lexically
encloses the throw point. All catch-blocks associated with that
try-block are considered in lexical order. If no catch-block is found
that can handle the run-time type of the exception, the function that
called the current function is searched for a lexically enclosing
try-block that encloses the call to the current function. This process
continues until a catch-block is found that can handle the current
exception.
If a matching catch-block is located, the Engine prepares to transfer
control to the first statement of that catch-block. However, before
execution of that catch-block can start, the Engine first executes, in
order, any finally-blocks associated with try-blocks nested more deeply
than the one that caught the exception.
If no matching catch-block is found, the behavior is
implementation-defined.
**Examples**
```Hack
function getTextLines(string $filename): Continuation
inclusion-directive:
require-multiple-directive
require-once-directive
**Defined elsewhere**
* [*require-multiple-directive*](12-script-inclusion.md#the-require-directive)
* [*require-once-directive*](12-script-inclusion.md#the-require_once-directive)
**Semantics:**
When creating large applications or building component libraries, it is
useful to be able to break up the source code into small, manageable
pieces each of which performs some specific task, and which can be
shared somehow, and tested, maintained, and deployed individually. For
example, a programmer might define a series of useful constants and use
them in numerous and possibly unrelated applications. Likewise, a set of
class definitions can be shared among numerous applications needing to
create objects of those types.
An *include file* is a script that is suitable for *inclusion* by
another script. The script doing the including is the *including file*,
while the one being included is the *included file*. A script can be an
including file and an included file, either, or neither.
It is important to understand that unlike the C/C++ (or similar)
preprocessor, script inclusion in PHP is not a text substitution
process. That is, the contents of an included file are not treated as if
they directly replaced the inclusion operation source in the including
file.
The name used to specify an include file may contain an absolute or
relative path. In the latter case, an implementation may use the
configuration directive
[`include_path`](http://docs.hhvm.com/manual/en/ini.core.php#ini.include-path)
to resolve the include file's location.
## The `require` Directive
**Syntax**
require-multiple-directive: require include-filename ; include-filename: expression**Defined elsewhere** * [*expression*](10-expressions.md#yield-operator) **Constraints** *expression* must be a string that designates a file that exists, is accessible, and whose format is suitable for inclusion (that is, starts with a [Hack start-tag](04-basic-concepts.md#program-structure)). **Semantics:** If the designated file is not accessible, execution is terminated. Variables defined in an included file take on scope of the source line on which the inclusion occurs in the including file. However, functions and classes defined in the included file are given global scope. The library function [`get_included_files`](http://www.php.net/get_included_files) provides the names of all files included or required. **Examples** ```Hack require 'Point.php'; require ('Circle.php'); ``` ## The `require_once` Directive **Syntax**
require-once-directive:
require_once include-filename ;
**Defined elsewhere**
* [*include-filename*](12-script-inclusion.md#the-require-directive)
**Semantics:**
This operator is identical to operator [`require`](12-script-inclusion.md#the-require-directive) except that in
the case of `require_once`, the include file is included once only during
program execution.
**Examples**
```Hack
// Point.php
enum-declaration:
enum name enum-base type-constraintopt { enumerator-listopt }
enum-base:
: int
: string
enumerator-list:
enumerator
enumerator-list enumerator
enumerator:
enumerator-constant = constant-expression ;
enumerator-constant:
name
*name* is defined in [§§](09-lexical-structure.md#names); *type-constraint* is defined in [§§](05-types.md#general); and *constant-expression* is defined in [§§](10-expressions.md#constant-expressions).
**Constraints**
The underlying type designated by *enum-base* must be able to represent all the values of the enumerators defined in the *enumerator-list*.
If *type-constraint* is present, *enum-base* must be a subtype ([§§](05-types.md#supertypes-and-subtypes)) of *type-constraint*s *type-specifier*.
Each *constant-expression* must have type `int` or `string`.
The *names* of *enumeration-constants* declared in the same *enum-declaration* must be distinct.
A *constant-expression* must not refer directly or indirectly to the *name* of its own *enumeration-constant*.
**Semantics**
An *enum-declaration* defines an enumerated type by the name *name*. Enumerated type names are case-preserved ([§§](03-terms-and-definitions.md).
The *name*s in an *enumerator-list* are declared as constants. Multiple *enumeration-constants* declared in the same *enum-declaration* may have the same *constant-expression* value. Different enumerated types can have *enumeration-constants* with the same *name*. When used, each *name* is qualified by prepending its parent enumerated type *name* and "`::`", in that order.
The type of each *enumeration-constant* is the type specified by *type-constraint*, if present; otherwise, the type of each *enumeration-constant* is the enumerated type in which it is defined.
An *enumeration-constant* can be used in any read-only context for an expression of its type.
A *constant-expression* can refer to the *name*s of other *enumeration-constants* in the same enumerated type. However, it must use their qualified names.
**Examples**
```Hack
enum BitFlags: int as int {
F1 = 1;
F2 = BitFlags::F1 << 1;
F3 = BitFlags::F2 << 1;
}
// -----------------------------------------
enum ControlStatus: int {
Stopped = 0;
Stopping = 1;
Starting = 2;
Started = 3;
}
function processStatus(ControlStatus $cs): void {
switch ($cs) {
case ControlStatus::Started:
…
break;
case ControlStatus::Starting:
…
break;
case ControlStatus::Stopped:
…
break;
case ControlStatus::Stopping:
…
break;
}
}
```
This example defines `ControlStatus` to be an enumerated type with an underlying type of `int`. The enumerated type has the four named enumeration constants `Stopped`, `Stopping`, `Starting`, and `Started`. Each enumeration constant is initialized with the integer constant value, as shown. When called, the function `processStatus` is passed an enum having one of the four possible enumeration constant values.
```Hack
enum Permission: string {
Read = 'R';
Write = 'W';
Execute = 'E';
Delete = 'D';
}
enum Colors: int {
Red = 3;
White = 5;
Blue = 10;
Default = 3; // duplicate value is okay
}
```
## The Predefined Enumerated Type Methods
All enumerated types behave as if they contained the following family of public, static methods.
```Hack
public static function assert(mixed $value): XXX
public static function assertAll(Traversablegeneric-type-parameter-list: < generic-type-parameters ,opt > generic-type-parameters: generic-type-parameter generic-type-parameters , generic-type-parameter generic-type-parameter: generic-type-parameter-varianceopt generic-type-parameter-name type-constraintopt generic-type-parameter-name: name generic-type-parameter-variance: + -*name* is defined in [§§](09-lexical-structure.md#names) and *type-constraint* is described in [§§](05-types.md#general). **Constraints** Within a *generic-type-parameter-list*, *name*s must be distinct. All *name*s must begin with the letter T. A *name* used in a *generic-type-parameter* of a method must not be the same as that used in a *generic-type-parameter* for an enclosing class, interface, or trait. *generic-type-parameter-variance* must not be present in a *function-definition* ([§§](15-functions.md#function-definitions)). The *type-specifier* in *generic-type-constraint* must not be `this` or `?this`. **Semantics** A type parameter is a placeholder for a type that is supplied when the generic type is instantiated or the generic method or function is invoked. A type parameter is a compile-time construct. At run-time, each type parameter is matched to a run-time type that was specified by a type argument. Therefore, a type declared with a type parameter will, at run-time, be a closed generic type ([§§](14-generic-types-methods-and-functions.md#open-and-closed-generic-types)), and execution involving a type parameter uses the actual type that was supplied as the type argument for that type parameter. The *name* of a type parameter is visible from its point of definition through the end of the type, method, or function declaration on which it is defined. However, the *name* does not conflict with a *name* of the same spelling used in non-type contexts (such as the names of a class constant, an attribute, a method, an enum constant, or a namespace). Generic type constraints are discussed in [§§](14-generic-types-methods-and-functions.md#type-constraints). *generic-type-parameter-variance* indicates the variance for that parameter: `+` for covariance, `- `for contravariance. If *generic-type-parameter-variance* is omitted, covariance is assumed. **Examples** In the following case, class `Vector` has one type parameter, `Tv`. Method `map` also has one type parameter, `Tu`. ```Hack final class Vector
generic-type-argument-list: < generic-type-arguments ,opt > generic-type-arguments: generic-type-argument generic-type-arguments , generic-type-argument generic-type-argument: type-specifier name*name* is defined in [§§](09-lexical-structure.md#names) and *type-specifier* is described in [§§](05-types.md#general). **Constraints** Each *generic-type-argument* must satisfy any constraint on the corresponding type parameter ([§§](14-generic-types-methods-and-functions.md#type-parameters)). **Semantics** A *generic-type-argument* can be a *type-specifier* or a *name* that is a *type-parameter*. Either way, at runtime, it is used in place of the corresponding type parameter. A *generic-type-argument* can either be open or closed ([§§](14-generic-types-methods-and-functions.md#open-and-closed-generic-types)). **Examples** ```Hack final class Pair
function-definition:
attribute-specificationopt function-definition-no-attribute
function-definition-no-attribute:
function-definition-header compound-statement
function-definition-header:
asyncopt function name generic-type-parameter-listopt ( parameter-listopt ) : return-type
parameter-list:
...
parameter-declaration-list ,opt
parameter-declaration-list , ...
parameter-declaration-list:
parameter-declaration
parameter-declaration-list , parameter-declaration
parameter-declaration:
attribute-specificationopt type-specifier variable-name default-argument-specifieropt
default-argument-specifier:
= const-expression
return-type:
type-specifier
noreturn
**Defined elsewhere**
* [*attribute-specification*](21-attributes.md#attribute-specification)
* [*compound-statement*](11-statements.md#compound-statements)
* [*const-expression*](10-expressions.md#constant-expressions)
* [*generic-type-parameter-list*](14-generic-types-methods-and-functions.md#type-parameters)
* [*name*](09-lexical-structure.md#names)
* [*type-specifier*](05-types.md#general)
* [*variable-name*](09-lexical-structure.md#names)
**Constraints**
The name of a method must not be the same as that of its parent class.
Each *variable-name* in a *parameter-declaration-list* must be distinct.
If any *parameter-declaration* has a *default-argument-specifier*, then all subsequent *parameter-declarations* in the same *parameter-declaration-list* must also have a *default-argument-specifier*.
If *return-type* is `noreturn`, the *compound-statement* must not contain any [`return` statements](11-statements.md#the-return-statement).
If the *type-specifier* in *return-type* is `void`, the *compound-statement* must not contain any [`return` statements](11-statements.md#the-return-statement) having an *expression*. Otherwise, all `return` statements must contain an *expression* whose type is a subtype of the type indicated by *type-specifier*.
If *async* is present, *return-type* must be a type that implements [`Awaitable
class-declaration:
attribute-specificationopt class-modifieropt class name generic-type-parameter-listopt class-base-clauseopt
class-interface-clauseopt { trait-use-clausesopt class-member-declarationsopt }
class-modifier:
abstract
final
abstract final
class-base-clause:
extends qualified-name generic-type-argument-listopt
class-interface-clause:
implements qualified-name generic-type-argument-listopt
class-interface-clause , qualified-name generic-type-argument-listopt
**Defined elsewhere**
* [*attribute-specification*](21-attributes.md#attribute-specification)
* [*class-member-declarations*](16-classes.md#class-members)
* [*generic-type-argument-list*](14-generic-types-methods-and-functions.md#type-parameters)
* [*generic-type-parameter-list*](14-generic-types-methods-and-functions.md#type-parameters)
* [*name*](09-lexical-structure.md#names)
* [*qualified-name*](20-namespaces.md#defining-namespaces)
* [*trait-use-clauses*](18-traits.md#trait-declarations)
**Constraints**
A class must not be derived directly or indirectly from itself.
A *class-declaration* containing any *class-member-declarations* that
have the modifier `abstract` must itself have an `abstract`
*class-modifier*.
*class-base-clause* must not name a final class.
*qualified-name* in *class-base-clause* must name a class type, and must
not be `parent`, `self`, or `static`.
A concrete class must implement each of the methods from all the
[interfaces](17-interfaces.md#general) specified in *class-interface-clause*, using the
exact same signature as defined in each interface.
*qualified-name* in *class-interface-clause* must name an interface
type.
A generic class and a non-generic class in the same scope cannot have the same *name*.
**Semantics**
A *class-declaration* defines a class type by the name *name*. Class
names are [case-preserved](03-terms-and-definitions.md).
The `abstract` modifier declares a class usable only as a base class; the
class cannot be instantiated directly. An abstract class may contain one
or more abstract members, but it is not required to do so. When a
concrete class is derived from an abstract class, the concrete class
must include an implementation for each of the abstract members it
inherits.
The `final` modifier prevents a class from being used as a base class.
The optional *class-base-clause* specifies the one base class from which
the class being defined is derived. In such a case, the derived class
inherits all the members from the base class.
The optional *class-interface-clause* specifies the one or more
interfaces that are implemented by the class being defined.
A class is required to implement a given interface in either of the following cases:
* If its *class-declaration* specifies that interface directly in a *class-interface-clause*; or
* If that class contains a *trait-use-clause* for a trait whose *trait-declaration* contains a *class-interface-clause* naming that interface; or
* Both.
A class can use one or more traits via a *trait-use-clauses*; see [§§](18-traits.md#general)
and [§§](18-traits.md#trait-declarations).
**Examples**
```Hack
abstract class Vehicle {
public abstract function getMaxSpeed(): int;
…
}
abstract class Aircraft extends Vehicle {
public abstract function getMaxAltitude(): int;
…
}
class PassengerJet extends Aircraft {
public function getMaxSpeed(): int {
// implement method
}
public function getMaxAltitude(): int {
// implement method
}
…
}
$pj = new PassengerJet(…);
echo "\$pj's maximum speed: " . $pj->getMaxSpeed() . "\n";
echo "\$pj's maximum altitude: " . $pj->getMaxAltitude() . "\n";
// -----------------------------------------
final class MathLibrary {
private function MathLibrary() {} // disallows instantiation
public static function sin(float $p): float { … }
…
}
$v = MathLibrary::sin(2.34);
// -----------------------------------------
interface MyCollection {
function put(int $item): void;
function get(): int;
}
class MyList implements MyCollection {
public function put(int $item): void {
// implement method
}
public function get(): int {
// implement method
}
…
}
```
## Class Members
**Syntax**
class-member-declarations:
class-member-declaration
class-member-declarations class-member-declaration
class-member-declaration:
const-declaration
property-declaration
method-declaration
constructor-declaration
destructor-declaration
type-constant-declaration
**Defined elsewhere**
* [*const-declaration*](16-classes.md#constants)
* [*constructor-declaration*](16-classes.md#constructors)
* [*destructor-declaration*](16-classes.md#destructors)
* [*method-declaration*](16-classes.md#methods)
* [*property-declaration*](16-classes.md#properties)
* [*type-constant-declaration*](16-classes.md#type-constants)
**Semantics**
The members of a class are those specified by its
*class-member-declaration*s, and the members inherited from its base
class, from the interfaces it implements, and from the traits that it uses. (A class may also contain dynamic members, as described in [§§](16-classes.md#dynamic-methods).
However, as these have no compile-time names, they can only be accessed
via method calls.)
A class may contain the following members:
* [Constants](16-classes.md#constants) – the constant values associated with the class.
* [Properties](16-classes.md#properties) – the variables of the class.
* [Methods](16-classes.md#methods) – the computations and actions that can be performed by the class (see also [§§](16-classes.md#methods-with-special-semantics)).
* [Constructor](16-classes.md#constructors) – the actions required to initialize an instance of the class.
* [Destructor](16-classes.md#destructors) – the actions to be performed when an instance of the class is no longer needed.
* [Type constant](16-classes.md#type-constants) – a way of parameterizing class types without using generics.
A number of names are reserved for methods with special semantics, which
user-defined versions must follow. These are described in ([§§](16-classes.md#methods-with-special-semantics)).
Methods and properties can either be *static* or *instance* members. A
static member is declared using `static`. An instance member is one that
is not static. The name of a static method or property can never be used
on its own; it must always be used as the right-hand operand of the
[scope resolution operator](10-expressions.md#scope-resolution-operator). The name of an instance method or
property can never be used on its own; it must always be used as the
right-hand operand of the[ member selection operator](10-expressions.md#member-selection-operator).
Each instance of a class contains its own, unique set of instance
properties of that class. An instance member is accessed via the
[`->` operator](10-expressions.md#member-selection-operator). In contrast, a static property designates
exactly one VSlot for its class, which does not belong to any instance,
per se. A static property exists whether or not any instances of that
class exist. A static member is accessed via the [`::` operator](10-expressions.md#scope-resolution-operator).
When any instance method operates on a given instance of a class, within
that method that object can be accessed via [`$this`](10-expressions.md#general-1). As a
static method does not operate on a specific instance, it has no `$this`.
**Examples**
```Hack
class Point {
private static int $pointCount = 0; // static property
private float $x; // instance property
private float $y; // instance property
public static function getPointCount(): int { // static method
return self::$pointCount; // access static property
}
public function move(num $x, num $y): void {// instance method
$this->x = (float)$x;
$this->y = (float)$y;
}
public function __construct(num $x = 0, num $y = 0) { // instance method
$this->x = (float)$x; // access instance property
$this->y = (float)$y; // access instance property
++self::$pointCount; // access static property
}
public function __destruct() { // instance method
--self::$pointCount; // access static property
…
}
…
}
echo "Point count = " . Point::getPointCount() . "\n";
$cName = 'Point';
echo "Point count = " . $cName::getPointCount() . "\n";
```
## Dynamic Methods
Ordinarily, all of the instance methods of a class are
declared explicitly in that class's definition. However, under certain circumstances, *dynamic
methods* can be added to a particular instance of a class or to the
class as a whole at runtime.
With a dynamic method, no method is really added to the
instance or the class. However, the illusion of doing that is achieved
by allowing a call to an instance or static method, but one which is not
declared in that instance's class, to be accepted, intercepted by a
method called [`__call`](16-classes.md#method-__call) or [`__callStatic`](16-classes.md#method-__callstatic), and
dealt with under program control.
Consider the following code fragment, in which class Widget has neither
an instance method called `iMethod` nor a static method called `sMethod`,
but that class has made provision to deal with dynamic methods:
```Hack
$obj = new Widget();
$obj->iMethod(10, true, "abc");
Widget::sMethod(null, 1.234);
```
The call to `iMethod` is treated as if it were
```Hack
$obj->__call('iMethod', array(10, true, "abc"))
```
and the call to `sMethod` is treated as if it were
```Hack
Widget::__callStatic('sMethod', array(null, 1.234))
```
## Constants
**Syntax**
const-declaration:
abstractopt const type-specifieropt constant-declarator-list ;
constant-declarator-list:
constant-declarator
constant-declarator-list , constant-declarator
constant-declarator:
name constant-initializeropt
constant-initializer:
= const-expression
**Defined elsewhere**
* [*const-expression*](10-expressions.md#constant-expressions)
* [*name*](09-lexical-structure.md#names)
* [*type-specifier*](05-types.md#general)
**Constraints**
A *const-declaration* must be
a *class constant* (inside a [*class-definition*](16-classes.md#class-members) or be an
*interface constant* (inside an [*interface-definition*](17-interfaces.md#interface-members).
If `abstract` is present, no *constant-initializer*s are permitted. If `abstract` is absent, each *constant-declarator* must have a *constant-initializer*.
**Semantics**
A *const-declaration* defines a c-constant.
All class constants have public visibility.
All constants are implicitly `static`.
If *type-specifier* is omitted, the type is inferred from *const-expression*.
Note: Although the grammar allows a class constant to have any type, there is no way to write a *constant-expression* for closures, tuples, or shapes.
**Examples:**
```Hack
class Automobile {
const DEFAULT_COLOR = "white";
…
}
$col = Automobile::DEFAULT_COLOR;
```
## Properties
**Syntax**
property-declaration:
property-modifier type-specifier property-declarator-list ;
property-declarator-list:
property-declarator
property-declarator-list , property-declarator
property-declarator:
variable-name property-initializeropt
property-modifier:
visibility-modifier static-modifieropt
static-modifier visibility-modifier
visibility-modifier:
public
protected
private
static-modifier:
static
property-initializer:
= expression
**Defined elsewhere**
* [*constant-expression*](10-expressions.md#yield-operator)
* [*type-specifier*](05-types.md#general)
* [*variable-name*](09-lexical-structure.md#names)
**Constraints**
A static property cannot have a *type-specifier* of the form `this` `::` *name*.
A static property cannot have a *type-specifier* of `this` or `?this`.
**Semantics**
A *property-declaration* defines an instance or static property called *variable-name*.
The visibility modifiers are described in [§§](16-classes.md#general). The `static` modifier is described in [§§](16-classes.md#class-members).
The *property-initializer*s for instance properties are applied prior to
the class's constructor being called.
All properties of non-nullable type must be initialized explicitly either by a *property-initializer* or by the constructor. Properties of nullable type that are not explicitly initialized take on the value `null`.
**Examples**
```Hack
class Point {
private static int $pointCount = 0; // static property with initializer
private float $x; // instance property
private float $y; // instance property
…
}
```
## Methods
**Syntax**
method-declaration:
p
attribute-specificationopt method-modifiers function-definition-no-attribute
attribute-specificationopt method-modifiers function-definition-header ;
method-modifiers:
method-modifier
method-modifiers method-modifier
method-modifier:
visibility-modifier
static-modifier
abstract
final
**Defined elsewhere**
* [*function-definition*](15-functions.md#function-definitions)
* [*function-definition-header*](15-functions.md#function-definitions)
* [*static-modifier*](16-classes.md#class-members)
* [*visibility-modifier*](16-classes.md#general)
**Constraints**
When defining a concrete class that inherits from an abstract class, the
definition of each abstract method inherited by the derived class must
have the same or a
less-restricted [visibility](http://docs.hhvm.com/manual/en/language.oop5.visibility.php)
than in the corresponding abstract declaration. Furthermore, the
signature of a method definition must match that of its abstract
declaration.
The *method-modifiers* preceding a *function-definition* must not contain
the `abstract` modifier.
The *method-modifiers* preceding a *function-definition-header* must
contain the `abstract` modifier.
A method must not have the same modifier specified more than once. A
method must not have more than one *visibility-modifier*. A method must
not have both the modifiers `abstract` and `private`, or `abstract` and `final`.
An abstract method must not also be asynchronous. However, an abstract method can have a return-type of `Awaitable
constructor-declaration:
attribute-specificationopt constructor-modifiers function __construct (
constructor-parameter-declaration-listopt ) void-returnopt compound-statement
constructor-parameter-declaration-list:
constructor-parameter-declaration
constructor-parameter-declaration-list , constructor-parameter-declaration
constructor-parameter-declaration:
visibility-modifieropt type-specifier variable-name default-argument-specifieropt
constructor-modifiers:
constructor-modifier
constructor-modifiers constructor-modifier
constructor-modifier:
visibility-modifier
abstract
final
**Defined elsewhere**
* [*attribute-specification*](21-attributes.md#attribute-specification)
* [*compound-statement*](11-statements.md#compound-statements)
* [*default-argument-specifier*](14-generic-types-methods-and-functions.md#type-constraints)
* [*type-specifier*](05-types.md#general)
* [*variable-name*](09-lexical-structure.md#names)
* [*visibility-modifier*](16-classes.md#properties)
**Constraints**
An overriding constructor in a derived class must have the same or a
less-restricted [visibility](http://docs.hhvm.com/manual/en/language.oop5.visibility.php)
than that being overridden in the base class.
The *variable-name* in a *constructor-parameter-declaration* containing a *visibility-modifier* must not be the same as an explicitly declared property in this class.
*compound-statement* must not contain a call to a non-private method in the same class.
**Semantics**
A constructor is a specially named [instance method](16-classes.md#methods) that is used
to initialize an instance immediately after it has been created. Any
instance properties of nullable type not explicitly initialized by a constructor take on
the value `null`.
Constructors can be overridden in a derived class by redeclaring them.
However, an overriding constructor need not have the same signature as
defined in the base class.
Constructors are called by [*object-creation-expression*s](10-expressions.md#the-new-operator)
and from within other constructors.
The `abstract` and `final` modifiers are described in [§§](16-classes.md#methods).
If classes in a derived-class hierarchy have constructors, it is the
responsibility of the constructor at each level to call the constructor
in its base-class explicitly, using the notation
`parent::__construct(...)`. If a constructor calls its base-class
constructor, it should do so as the first statement in
*compound-statement*, so the object hierarchy is built from the
bottom-up. A constructor should not call its base-class constructor more
than once. A call to a base-class constructor searches for the nearest
constructor in the class hierarchy. Not every level of the hierarchy
need have a constructor.
When a *constructor-parameter-declaration* contains a *visibility-modifier*, a property called *variable-name* with visibility *visibility-modifier* is added to the current class. When that constructor is called, the value of the argument for that parameter is assigned to the added property. Note: This feature simply provides a programming shortcut by having the implementation declare and initialize such properties.
A constructor does not require a return type annotation; if one is included, it must be void.
**Examples**
```Hack
class Point {
private static int $pointCount = 0;
public function __construct(private float $x = 0.0, private float $y = 0.0) {
// private properties $x and $y are created and initialized
++self::$pointCount;
}
public function __destruct() {
--self::$pointCount;
…
}
…
}
// -----------------------------------------
class MyRangeException extends Exception {
public function __construct(string $message, /* whatever */ ) {
parent::__construct($message);
…
}
…
}
```
## Destructors
**Syntax**
destructor-declaration:
attribute-specificationopt visibility-modifier function __destruct ( ) void-returnopt compound-statement
void-return:
: void
**Defined elsewhere**
* [*attribute-specification*](21-attributes.md#attribute-specification)
* [*compound-statement*](11-statements.md#compound-statements)
* [*visibility-modifier*](16-classes.md#general)
**Constraints**
An overriding destructor in a derived class must have the same or a
less-restricted [visibility](http://www.php.net/manual/en/language.oop5.visibility.php)
than that being overridden in the base class.
**Semantics**
A destructor is a special-named [instance method](16-classes.md#methods) that is used to
free resources when an instance is no longer needed. The destructors for
instances of all classes are called automatically once there are no
handles pointing to those instances or in some unspecified order during
program shutdown.
Destructors can be overridden in a derived class by redeclaring them.
Destructors are called by the Engine or from within other destructors.
If classes in a derived-class hierarchy have destructors, it is the
responsibility of the destructor at each level to call the destructor in
the base-class explicitly, using the notation `parent::__destruct()`. If
a destructor calls its base-class destructor, it should do so as the
last statement in *compound-statement*, so the object hierarchy is
destructed from the top-down. A destructor should not call its
base-class destructor more than once. A call to a base-class destructor
searches for the nearest destructor in the class hierarchy. Not every
level of the hierarchy need have a destructor. A `private` destructor
inhibits destructor calls from derived classes.
A destructor does not require a return type annotation; if one is included, it must be void.
**Examples**
See [§§](#constructors) for an example of a constructor and destructor.
## Type Constants
**Syntax**
type-constant-declaration:
abstract-type-constant-declaration
concrete-type-constant-declaration
abstract-type-constant-declaration:
abstract const type name type-constraintopt ;
concrete-type-constant-declaration:
const type name type-constraintopt = type-specifier ;
**Defined elsewhere**
* [*name*](09-lexical-structure.md#names)
* [*type-constraint*](05-types.md#general)
* [*type-specifier*](05-types.md#general)
**Constraints**
A class or interface must not have multiple *type-constant-declaration*s for the same *name*.
A class having an *abstract-type-constant-declaration* must be abstract. (Any class that defines an abstract type constant must be abstract itself, and any class that inherits an abstract type constant must be either abstract itself or override it with a concrete type constant.
An interface must not contain a *concrete-type-constant-declaration* that has a *type-constraint*.
When overriding a type constant having a *type-constraint*, the overriding type must be a subtype of the constraint type.
A concrete type constant without a *type-constraint* cannot be overridden.
*type-specifier* cannot designate a class type parameter.
By convention, *name* should begin with an uppercase `T`.
**Semantics**
Type constants provide an alternative to [parameterized types](14-generic-types,-methods,-and-functions.md#general). For example, a base class can define an abstract type constant---essentially a name without a concrete type attached---and subclasses each override that with a concrete type constant. Conceptually, type constants are to types, as abstract methods are to methods.
A type constant has public [visibility](16-classes.md#general) and is implicitly [static](16-classes.md#class-members).
*type-constraint* restricts the type by which a type constant can be overridden.
In an *abstract-type-constant-declaration*, the absence of a *type-constraint* is the same as the presence of one with a type of `mixed`. In a *concrete-type-constant-declaration*, the absence of a *type-constraint* prevents name from being overridden.
**Examples**
```Hack
interface I1 {
abstract const type T1 as arraykey;
public function getID1(): this::T1;
const type T4a = int;
}
interface I2 {
abstract const type T2;
public function getID2(this::T2 $p): void;
abstract const type T3;
const type T4c = string;
}
interface I3 extends I2 {
public function f(this::T2 $p): void;
}
class Ctc6 implements I1, I2 {
const type T1 = int;
public function __construct(private this::T1 $id) {}
public function getID1(): this::T1 {
return $this->id;
}
const type T2 = string;
public function getID2(this::T2 $p): void {}
const type T3 = float;
public function f(this::T4a $p1, this::T4c $p2): void {}
}
// -----------------------------------------
abstract class CBase {
abstract const type T;
public function __construct(protected this::T $value) {}
}
class Cstring extends CBase {
const type T = string;
public function getString(): string {
return $this->value; // gets the string
}
}
class Cint extends CBase {
const type T = int;
public function getInt(): int {
return $this->value; // gets the int
}
}
function run2(): void {
var_dump((new Cstring('abc'))->getString());
var_dump((new Cint(123))->getInt());
}
```
## Methods with Special Semantics
### General
If a class contains a definition for a method having one of the
following names, that method must have the prescribed visibility,
signature, and semantics:
Method Name | Description
------------|-------------
[`__call`](16-classes.md#method-__call) | Calls a dynamic method in the context of an instance-method call
[`__callStatic`](16-classes.md#method-__callstatic) | Calls a dynamic method in the context of a static-method call
[`__clone`](16-classes.md#method-__clone) | Typically used to make a deep copy of an object
[`__construct`](16-classes.md#constructors) | A constructor
[`__destruct`](16-classes.md#destructors) | A destructor
[`__sleep`](16-classes.md#method-__sleep) | Executed before [serialization](16-classes.md#serialization) of an instance of this class
[`__toString`](16-classes.md#method-__tostring) | Returns a string representation of the instance on which it is called
[`__wakeup`](16-classes.md#method-__wakeup) | Executed after [unserialization](16-classes.md#serialization) of an instance of this class
### Method `__call`
**Syntax**
public function __call ( string $name , array<mixed> $arguments ) : mixed compound-statement**Defined elsewhere** * [*compound-statement*](11-statements.md#compound-statements) **Semantics** This instance method is called to invoke the [dynamic method](16-classes.md#dynamic-methods) designated by `$name` using the arguments specified by the elements of the array designated by `$arguments`. It can return any value deemed appropriate. Typically, `__call` is called implicitly, when the [`->` operator](10-expressions.md#member-selection-operator) is used to call an instance method that is not visible. While a method-name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic method name designated by *$name*. Any source character is allowed here. **Examples** ```Hack class Widget { public function __call(string $name, array
public static function __callStatic ( string $name , array<mixed> $arguments ) : mixed
compound-statement
**Defined elsewhere**
* [*compound-statement*](11-statements.md#compound-statements)
**Semantics**
This static method is called to invoke the [dynamic method](16-classes.md#dynamic-methods)
designated by `$name` using the arguments specified by the elements of
the array designated by `$arguments`. It can return any value deemed
appropriate.
Typically, `__callStatic` is called implicitly, when the [`::` operator](10-expressions.md#scope-resolution-operator) is used to call a static method that is not visible. Now while
`__callStatic` can be called explicitly, the two scenarios do not
necessarily produce the same result. Consider the expression `C::m(...)`,
where `C` is a class and `m` is a static-method name. If `m` is the name of a
visible method, `C::m(...)` does not result in `__callStatic`'s being
called. Instead, the visible method is used. On the other hand, the
expression `C::__callStatic('m',array(...))` always calls the named
dynamic method, ignoring the fact that a static visible method having
the same name might exist. If m is not the name of a visible method, the
two expressions are equivalent; that is; when handling `C::m(...)`, if no
visible method by that name is found, a dynamic method is assumed, and
`__callStatic` is called. (Note: While it would be unusual to create
deliberately a static dynamic method with the same name as a static
visible one, the visible method might be added later. This name
"duplication" is convenient when adding a dynamic method to a class
without having to worry about a name clash with any method names that
class inherits.)
While a method-name source token has a prescribed syntax, there are no
restrictions on the spelling of the dynamic method name designated by
`$name`. Any source character is allowed here.
**Examples**
```Hack
class Widget {
public static function __callStatic(string $name,
arraypublic function __clone ( ) : void compound-statement**Defined elsewhere** * [*compound-statement*](11-statements.md#compound-statements) **Semantics** This instance method is called by the [`clone` operator](10-expressions.md#the-clone-operator), (typically) to make a [deep copy](04-basic-concepts.md#cloning-objects) of the current class component of the instance on which it is called. (Method `__clone` cannot be called directly by the program.) Consider a class `Employee`, from which is derived a class `Manager`. Let us assume that both classes contain properties that are objects. To make a copy of a `Manager` object, its `__clone` method is called to do whatever is necessary to copy the properties for the `Manager` class. That method should, in turn, call the `__clone` method of its parent class, `Employee`, so that the properties of that class can also be copied (and so on, up the derived-class hierarchy). To clone an object, the `clone` operator makes a [shallow copy](04-basic-concepts.md#cloning-objects)) of the object on which it is called. Then, if the class of the instance being cloned has a method called `__clone`, that method is automatically called to make a deep copy. Method `__clone` cannot be called directly from outside a class; it can only be called by name from within a derived class, using the notation `self::__clone()`. This method can return a value; however, if it does so and control returns directly to the point of invocation via the `clone` operator, that value will be ignored. The value returned to a `self::__clone()` call can, however, be retrieved. While cloning creates a new object, it does so without using a constructor, in which case, code may need to be added to the `__clone` method to emulate what happens in a corresponding constructor. (See the `Point` example below.) **Examples** ```Hack class Employee { … public function __clone(): void { // do what it takes here to make a copy of Employee object properties } } class Manager extends Employee { … public function __clone(): void { parent::__clone(); // request cloning of the Employee properties // do what it takes here to make a copy of Manager object properties } … } // ----------------------------------------- class Point { private static int $pointCount = 0; public function __construct(float $x = 0.0, float $y = 0.0) { … ++self::$pointCount; } public function __clone(): void { ++self::$pointCount; // emulate the constructor } … } $p1 = new Point(); // created using the constructor $p2 = clone $p1; // created by cloning ``` ### Method `__sleep` **Syntax**
public function __sleep ( ) : array<string> compound-statement**Defined elsewhere** * [*compound-statement*](11-statements.md#compound-statements) **Semantics** The instance methods [`__sleep` and `__wakeup`](16-classes.md#method-__wakeup) support [serialization](16-classes.md#serialization). If a class has a `__sleep` method, the library function [`serialize`](http://www.php.net/serialize) calls that method to find out which visible instance properties it should serialize. (In the absence of a `__sleep` or `serialize` method, all such properties are serialized.) This information is returned by `__sleep` as an array of zero or more elements, where each element's value is distinct and is the name of a visible instance property. These properties' values are serialized in the order in which the elements are inserted in the array. If `__sleep` does not return a value explicitly, `null` is returned, and that value is serialized. Besides creating the array of property names, `__sleep` can do whatever else might be needed before serialization occurs. Consider a `Point` class that not only contains x- and y-coordinates, it also has an `id` property; that is, each distinct `Point` created during a program's execution has a unique numerical id. However, there is no need to include this when a `Point` is serialized. It can simply be recreated when that `Point` is unserialized. This information is transient and need not be preserved across program executions. (The same can be true for other transient properties, such as those that contain temporary results or run-time caches.) In the absence of methods `__sleep` and `__wakeup`, instances of derived classes can be serialized and unserialized. However, it is not possible to perform customize serialization using those methods for such instances. For that, a class must implement the interface [`Serializable`](17-interfaces.md#interface-iteratoraggregate). **Examples** ```Hack class Point { private static int $nextId = 1; private float $x; private float $y; private int $id; public function __construct(float $x = 0.0, float $y = 0.0) { $this->x = $x; $this->y = $y; $this->id = self::$nextId++; // assign the next available id } public function __sleep(): array
public function __toString ( ) : string compound-statement**Defined elsewhere** * [*compound-statement*](11-statements.md#compound-statements) **Constraints** This function must not throw any exceptions. **Semantics** This instance method is intended to create a string representation of the instance on which it is called. If the instance's class is derived from a class that has or inherits a `__toString` method, the result of calling that method should be prepended to the returned string. `__toString` is called by a number of language and library facilities, including `echo`, when an object-to-string conversion is needed. `__toString` can be called directly. **Examples** ```Hack class Point { private float $x; private float $y; public function __construct(float $x = 0.0, float $y = 0.0) { $this->x = $x; $this->y = $y; } public function __toString(): string { return '(' . $this->x . ',' . $this->y . ')'; } … } $p1 = new Point(20, 30); echo $p1 . "\n"; // implicit call to __toString() returns "(20,30)" // ----------------------------------------- class MyRangeException extends Exception { public function __toString(): string { return parent::__toString() . string-representation-of-MyRangeException } … } ``` ### Method `__wakeup` **Syntax**
public function __wakeup ( ) : void compound-statement**Defined elsewhere** * [*compound-statement*](11-statements.md#compound-statements) **Semantics** The instance methods [`__sleep` and `__wakeup`](16-classes.md#method-__sleep) support [serialization](16-classes.md#serialization)). When the library function [`unserialize`](http://www.php.net/unserialize) is called on the string representation of an object, as created by the library function [`serialize`](http://www.php.net/serialize), `unserialize` creates an instance of that object's type **without calling a constructor**, and then calls that class's `__wakeup` method, if any, to initialize the instance. In the absence of a `__wakeup` method, all that is done is that the values of the instance properties encoded in the serialized string are restored. Consider a `Point` class that not only contains x- and y-coordinates, it also has an `id` property; that is, each distinct `Point` created during a program's execution has a unique numerical id. However, there is no need to include this when a `Point` is serialized. It can simply be recreated by `__wakeup` when that `Point` is unserialized. This means that `__wakeup` must emulate the constructor, as appropriate. **Examples** See [§§](16-classes.md#method-__sleep). ## Serialization In Hack, variables can be converted into some external form suitable for use in file storage or inter-program communication. The process of converting to this form is known as *serialization* while that of converting back again is known as *unserialization*. These facilities are provided by the library functions [`serialize`](http://www.php.net/serialize) and [`unserialize`](http://www.php.net/unserialize), respectively. (Library function [`serialize_memoize_param`](http://www.php.net/serialize_memoize_param) helps when serializing parameters to async functions.) In the case of variables that are objects, on their own, these two functions serialize and unserialize all the instance properties, which may be sufficient for some applications. However, if the programmer wants to customize these processes, they can do so in one of two, mutually exclusive ways. The first approach is to define methods called `__sleep` and `__awake`, and have them get control before serialization and after serialization, respectively. For information on this approach, see [§§](16-classes.md#method-__sleep) and [§§](16-classes.md#method-__wakeup). The second approach involves implementing the interface [`Serializable`](17-interfaces.md#interface-Serializable) by defining two methods, `serialize` and `unserialize`. Consider a `Point` class that not only contains x- and y-coordinates, it also has an `id` property; that is, each distinct `Point` created during a program's execution has a unique numerical id. However, there is no need to include this when a `Point` is serialized. It can simply be recreated when that `Point` is unserialized. This information is transient and need not be preserved across program executions. (The same can be true for other transient properties, such as those that contain temporary results or run-time caches.) Furthermore, consider a class `ColoredPoint` that extends `Point` by adding a `color` property. The following code shows how these classes need be defined in order for both `Points` and `ColoredPoints` to be serialized and unserialized: ```Hack class Point implements Serializable { // note the interface private static int $nextId = 1; private float $x; private float $y; private int $id; // transient property; not serialized public function __construct(float $x = 0.0, float $y = 0.0) { $this->x = $x; $this->y = $y; $this->id = self::$nextId++; } public function __toString(): string { return 'ID:' . $this->id . '(' . $this->x . ',' . $this->y . ')'; } public function serialize(): string { return serialize(array('y' => $this->y, 'x' => $this->x)); } ``` The custom method `serialize` calls the library function `serialize` to create a string version of the array, whose keys are the names of the instance properties to be serialized. The insertion order of the array is the order in which the properties are serialized in the resulting string. The array is returned. ```Hack public function unserialize(string $data): void { $data = unserialize($data); $this->x = $data['x']; $this->y = $data['y']; $this->id = self::$nextId++; } } ``` The custom method `unserialize` converts the serialized string passed to it back into an array. Because a new object is being created, but without any constructor being called, the `unserialize` method must perform the tasks ordinarily done by a constructor. In this case, that involves assigning the new object a unique id. ```Hack $p = new Point(2, 5); $s = serialize($p); ``` The call to the library function `serialize` calls the custom `serialize` method. Afterwards, the variable `$s` contains the serialized version of the `Point(2,5)`, and that can be stored in a database or transmitted to a cooperating program. The program that reads or receives that serialized string can convert its contents back into the corresponding variable(s), as follows: ```Hack $v = unserialize($s); ``` The call to the library function `unserialize` calls the custom `unserialize` method. Afterwards, the variable `$s` contains a new `Point(2,5)`. ```Hack class ColoredPoint extends Point implements Serializable { const RED = 1; const BLUE = 2; private int $color; // an instance property public function __construct(float $x = 0.0, float $y = 0.0, int $color = ColoredPoint::RED) { parent::__construct($x, $y); $this->color = $color; } public function __toString(): string { return parent::__toString() . $this->color; } public function serialize(): string { return serialize(array( 'color' => $this->color, 'baseData' => parent::serialize() )); } ``` As with class `Point`, this custom method returns an array of the instance properties that are to be serialized. However, in the case of the second element, an arbitrary key name is used, and its value is the serialized version of the base Point within the current `ColoredPoint` object. The order of the elements is up to the programmer. ```Hack public function unserialize(string $data): void { $data = unserialize($data); $this->color = $data['color']; parent::unserialize($data['baseData']); } } ``` As `ColoredPoint` has a base class, it unserializes its own instance properties before calling the base class's custom method, so it can unserialize the `Point` properties. ```Hack $cp = new ColoredPoint(9, 8, ColoredPoint::BLUE); $s = serialize($cp); ... $v = unserialize($s); ``` ## Predefined Classes ### Class `AsyncGenerator` This class supports the `yield` operator when dealing with asynchronous operations. This class cannot be instantiated directly. It is defined, as follows: ```Hack class AsyncGenerator
interface-declaration:
attribute-specificationopt interface name generic-type-parameter-listopt interface-base-clauseopt {
interface-member-declarationsopt }
interface-base-clause:
extends qualified-name generic-type-argument-listopt
interface-base-clause , qualified-name generic-type-argument-listopt
**Defined elsewhere**
* [*attribute-specification*](21-attributes.md#attribute-specification)
* [*generic-type-parameter-list*](14-generic-types-methods-and-functions.md#type-parameters)
* [*generic-type-argument-list*](14-generic-types-methods-and-functions.md#type-parameters)
* [*interface-member-declarations*](17-interfaces.md#interface-members)
* [*name*](09-lexical-structure.md#names)
* [*qualified-name*](20-namespaces.md#defining-namespaces)
**Constraints**
An interface must not be derived directly or indirectly from itself.
*qualified-name* must name an interface type.
A generic interface and a non-generic interface in the same scope cannot have the same *name*.
**Semantics**
An interface-declaration defines a contract that one or more classes can
implement.
Interface names are case-insensitive.
The optional *interface-base-clause* specifies the base interfaces from
which the interface being defined is derived. In such a case, the
derived interface inherits all the members from the base interfaces.
**Examples**
```Hack
interface MyCollection
interface-member-declarations:
interface-member-declaration
interface-member-declarations interface-member-declaration
interface-member-declaration:
require-extends-clause
const-declaration
method-declaration
type-constant-declaration
**Defined elsewhere**
* [*const-declaration*](16-classes.md#constants)
* [*method-declaration*](16-classes.md#methods)
* [*require-extends-clause*](18-traits.md#trait-members)
* [*type-constant-declaration*](16-classes.md#type-constants)
**Constraints**
The *qualified-name* in *requires-extends-clause* must designate a class name.
**Semantics**
The members of an interface are those specified by its
*interface-member-declaration*s, and the members inherited from its base
interfaces.
An interface may contain the following members:
* *require-extends-clauses* each of which requires the class implementing this interface to directly or indirectly extend the class type designated by *qualified-name*.
* [Constants](17-interfaces.md#constants) – the constant values associated with the interface.
* [Methods](17-interfaces.md#methods) – placeholders for the computations and actions that can be performed by implementers of the interface.
* [Type constants](16-classes.md#type-constants) – a way of parameterizing class types without using generics.
An *interface-member-declarations* may contain multiple *require-extends-clause*s that designate the same class, in which case, the duplicates are redundant.
## Constants
**Semantics**
An interface constant is just like a [class constant](16-classes.md#constants), except that
an interface constant cannot be overridden by a class that implements it
nor by an interface that extends it.
**Examples:**
```Hack
interface MyCollection
trait-declaration:
attribute-specificationopt trait name generic-type-parameter-listopt class-interface-clauseopt {
trait-use-clausesopt trait-member-declarationsopt }
trait-use-clauses:
trait-use-clause
trait-use-clauses trait-use-clause
trait-use-clause:
use trait-name-list ;
trait-name-list:
qualified-name generic-type-argument-listopt
trait-name-list , qualified-name generic-type-argument-listopt
**Defined elsewhere**
* [*attribute-specification*](21-attributes.md#attribute-specification)
* [*class-interface-clause*](16-classes.md#class-declarations)
* [*generic-type-argument-list*](14-generic-types-methods-and-functions.md#type-parameters)
* [*generic-type-parameter-list*](14-generic-types-methods-and-functions.md#type-parameters)
* [*name*](09-lexical-structure.md#names)
* [*trait-member-declarations*](18-traits.md#trait-members)
**Constraints**
The *name*s in *trait-name-list* must designate trait names, excluding
the name of the trait being declared.
A generic trait and a non-generic trait in the same scope cannot have the same name.
**Semantics**
A *trait-declaration* defines a named set of members, which are made
available to any class that uses that trait.
Trait names are [case-preserved](03-terms-and-definitions.md).
A *trait-declaration* may also use other traits. This is done via one or
more *trait-use-clause*s, each of which contains a comma-separated list
of trait names.
The optional *class-interface-clause* specifies the one or more interfaces that must be implemented by any class that uses this trait.
**Examples**
```Hack
trait T1 { public function compute( … ) : … { … } }
trait T2 { public function compute( … ) : … { … } }
trait T1 { public function sort( … ) : … { … } }
trait T4 {
use T3;
use T1, T2;
}
```
## Trait Members
**Syntax**
trait-member-declarations:
trait-member-declaration
trait-member-declarations trait-member-declaration
trait-member-declaration:
require-extends-clause
require-implements-clause
property-declaration
method-declaration
constructor-declaration
destructor-declaration
require-extends-clause:
require extends qualified-name ;
require-implements-clause:
require implements qualified-name ;
**Defined elsewhere**
* [*constructor-declaration*](16-classes.md#constructors)
* [*destructor-declaration*](16-classes.md#destructors)
* [*method-declaration*](16-classes.md#methods)
* [*property-declaration*](16-classes.md#properties)
* [*qualified-name*](20-namespaces.md#defining-namespaces)
**Constraints**
The *qualified-name* in *require-extends-clause* must designate the name of a class that does not directly use the trait being defined.
The *qualified-name* in *require-implements-clause* must designate the name of an interface that does not directly use the trait being defined.
**Semantics**
The members of a trait are those specified by its
*trait-member-declaration*s, and the members from any other traits it
uses.
A trait may contain the following members:
* *require-extends-clauses* each of which requires the class using this trait to directly or indirectly extend the class type designated by *qualified-name*.
* *require-implements-clauses* each of which requires the class using this trait to directly or indirectly implement the interface type designated by *qualified-name*.
* [Properties](16-classes.md#properties) – the variables made available to the class in which the trait is used.
* [Methods](16-classes.md#methods) – the computations and actions that can be performed by the class in which the trait is used. See also [§§](16-classes.md#methods-with-special-semantics).
* [Constructor](16-classes.md#constructors) – the actions required to initialize an instance of the class in which the trait is used.
* [Destructor](16-classes.md#destructors) – the actions to be performed when an instance of the class in which the trait is used is no longer needed.
*trait-member-declarations* may contain multiple *require-extends-clauses* that designate the same class, in which case, the duplicates are redundant.
*trait-member-declarations* may contain multiple *require-implements-clauses* that designate the same interface, in which case, the duplicates are redundant.
**Examples**
```Hack
trait T {
require extends C1;
private int $prop1 = 1000;
require implements I1;
protected static int $prop2;
public function compute( … ): void { … }
public static function getData( … ): void { … }
}
```
================================================
FILE: spec/19-exception-handling.md
================================================
# Exception Handling
## General
An *exception* is some unusual condition in that it is outside the
ordinary expected behavior. (Examples include dealing with situations in
which a critical resource is needed, but is unavailable, and detecting
an out-of-range value for some computation.) As such, exceptions require
special handling. This chapter describes how exceptions can be created
and handled.
Whenever some exceptional condition is detected at runtime, an exception
is *thrown*. A designated exception handler can *catch* the thrown
exception and service it. Among other things, the handler might recover
from the situation completely (allowing the script to continue
execution), it might perform some recovery and then throw an exception
to get further help, or it might perform some cleanup action and
terminate the script. Exceptions may be thrown on behalf of the Engine
or by explicit code source code in the script.
Exception handling involves the use of the following keywords:
* [`try`](11-statements.md#the-try-statement), which allows a *try-block* of code containing one or more possible exception generations, to be tried
* [`catch`](11-statements.md#the-try-statement), which defines a handler for a specific type of exception thrown from the corresponding try-block or from some function it calls
* [`finally`](11-statements.md#the-try-statement), which allows the *finally-block* of a try-block to be executed (to perform some cleanup, for example), whether or not an exception occurred within that try-block
* [`throw`](11-statements.md#the-throw-statement), which generates an exception of a given type, from a place called a *throw point*.
When an exception is thrown, an *exception object* of type [`\Exception`](19-exception-handling.md#class-exception), or of a subclass of that type, is created and made available to
the first catch-handler that can catch it. Among other things, the
exception object contains an *exception message* and an *exception
code*, both of which can be used by a handler to decide how to handle
the situation.
## Class `Exception`
Class `Exception` is the base class of all exception types. This class is
defined, as follows:
```Hack
class Exception {
protected string $message = 'Unknown exception';
protected int $code = 0;
protected string $file;
protected int $line;
protected ?Exception $previous = null;
public function __construct(string $message = "", int $code = 0,
?Exception $previous = null);
final private function __clone(): void;
final public function getMessage(): string;
final public function getCode(): int;
final public function getFile(): string;
final public function getLine(): int;
final public function getTrace(): array
namespace-definition:
namespace namespace-name ;
namespace namespace-nameopt { declaration-listopt }
namespace-name:
name
namespace-name \ name
namespace-name-as-a-prefix:
\
\opt namespace-name \
namespace \
namespace \ namespace-name \
qualified-name:
namespace-name-as-a-prefixopt name
**Defined elsewhere**
* [*declaration-list*](04-basic-concepts.md)
* [*name*](09-lexical-structure.md#names)
**Constraints**
Except for white space, the
first occurrence of a *namespace-definition* in a script must be the
first thing in that script.
All occurrence of a *namespace-definition* in a script must have the
*declaration-list* form or must have the "semicolon" form; the two forms
cannot be mixed.
When a script contains source code that is not inside a namespace, and
source code that is inside one or namespaces, the namespaced code must
use the *declaration-list* form of *namespace-definition*.
The *declaration-list* must not contain a *namespace-definition*.
**Semantics**
Namespace and sub-namespace names are [case-preserved](03-terms-and-definitions.md).
The pre-defined constant [`__NAMESPACE__`](06-constants.md#context-dependent-constants) contains the name of
the current namespace.
When the same namespace is defined in multiple scripts, and those
scripts are combined into the same program, the namespace is considered
the merger of its individual contributions.
In the "semicolon" form of *namespace-definition* the given
namespace extends until the end of the script, or until the lexically next
*namespace-definition*, whichever comes first. In the *declaration-list*
form the namespace extends from the opening brace to the closing brace.
**Examples**
Script1.php:
```Hack
namespace NS1;
... // __NAMESPACE__ is "NS1"
namespace NS3\Sub1;
... // __NAMESPACE__ is "NS3\Sub1"
```
Script2.php:
```Hack
namespace NS1
{
... // __NAMESPACE__ is "NS1"
}
namespace
{
... // __NAMESPACE__ is ""
}
namespace NS3\Sub1;
{
... // __NAMESPACE__ is "NS3\Sub1"
}
```
## Namespace Use Declarations**
**Syntax**
namespace-use-declaration:
use namespace-use-kindopt namespace-use-clauses ;
use namespace-use-kind namespace-name-as-a-prefix { namespace-use-clauses } ;
use namespace-name-as-a-prefix { namespace-use-kind-clauses } ;
namespace-use-clauses:
namespace-use-clause
namespace-use-clauses , namespace-use-clause
namespace-use-clause:
qualified-name namespace-aliasing-clauseopt
namespace-use-kind-clauses:
namespace-use-kind-clause
namespace-use-kind-clauses , namespace-use-kind-clause
namespace-use-kind-clause:
namespace-use-kindopt qualified-name namespace-aliasing-clauseopt
namespace-aliasing-clause:
as name
namespace-use-kind:
function
const
**Defined elsewhere**
* [*name*](09-lexical-structure.md#names)
* [*qualified-name*](#defining-namespaces)
**Constraints**
A *namespace-use-declaration* must not occur except at the pseudomain
level.
If the same *qualified-name* is imported multiple times in the same
scope, each occurrence must have a different alias.
**Semantics**
If a *namespace-use-kind* is specified before the clauses or group prefix,
then all subsequent clauses must name constants or functions, as appropriate.
Otherwise, if a *namespace-use-kind* is specified in a *namespace-use-kind-clause*
then the clause must name a constant or function, as appropriate.
Otherwise, the clause must name a namespace, class, interface or trait.
A *namespace-use-declaration* *imports*—that is, makes available—one or
more names into a scope, optionally giving them each an alias. Each of
those names may designate a namespace, a sub-namespace, a class, an
interface, or a trait. If a namespace-alias-clause is present, its
*name* is the alias for *qualified-name*. Otherwise, the right-most name
in *qualified-name* is the implied alias for *qualified-name*.
The "group" form of a *namespace-use-declaration* is a convenient syntax when
importing many members of a given namespace. The "group" form logically concatenates
the prefix onto the *qualified-name* in each clause. See the following section for
an example.
**Examples**
```Hack
namespace NS1 {
function f(): void { … }
class C { … }
interface I { … }
trait T { … }
}
namespace NS2 {
use \NS1\C, \NS1\I, \NS1\T;
class D extends C implements I {
use T;
}
\NS1\f(); // explicit namespace
use \NS1\C as C2; // C2 is an alias for the class name \NS1\C
$c2 = new C2;
}
```
The *namespace-use-declaration* in the example above could also be written in
"group" form as:
```
use \NS1\ { C, I, T };
```
================================================
FILE: spec/21-attributes.md
================================================
# Attributes
## General
Programmers can invent a new kind of declarative information, called an *attribute*. Attributes can be attached to various program entities, and information about those attribute can be retrieved at run-time via reflection (see library class `Reflection`, et al).
Consider the following example:
```Hack
<attribute-specification: << attribute-list >> attribute-list: attribute attribute-list , attribute attribute: attribute-name attribute-value-listopt attribute-name: name attribute-value-list: ( attribute-valuesopt ) attribute-values attribute-value attribute-values , attribute-value attribute-value: expression*name* is defined in [§§](09-lexical-structure.md#names); and *expression* is defined in [§§](10-expressions.md#yield-operator). **Constraints** The *name*s in an *attribute-list* must be distinct. The *expression*s in an *attribute-list* must be *constant-expressions* ([§§](10-expressions.md#constant-expressions)). **Semantics** A *name* in a user-defined attribute means whatever the programmer wants. The *name*s do not have any scope, per se. They appear only in the context of an *attribute-specification*, and do not hide nor conflict with the same names used in other contexts. Omitting *attribute-value-list* is equivalent to specifying it without *attribute-values*. **Examples** ```Hack <
input-file::
input-element
input-file input-element
input-element::
comment
white-space
token
### Comments
comment::
single-line-comment
delimited-comment
single-line-comment::
// input-charactersopt
# input-charactersopt
input-characters::
input-character
input-characters input-character
input-character::
Any source character except new-line
new-line::
Carriage-return character (U+000D)
Line-feed character (U+000A)
Carriage-return character (U+000D) followed by line-feed character (U+000A)
delimited-comment::
/* No characters or any source character sequence except /* */
### White Space
white-space::
white-space-character
white-space white-space-character
white-space-character::
new-line
Space character (U+0020)
Horizontal-tab character (U+0009)
### Tokens
#### General
token::
variable-name
name
keyword
literal
operator-or-punctuator
#### Names
variable-name::
$ name
name::
name-nondigit
name name-nondigit
name digit
name-nondigit::
nondigit
one of the characters U+007f–U+00ff
nondigit:: one of
_
a b c d e f g h i j k l m
n o p q r s t u v w x y z
A B C D E F G H I J K L M
N O P Q R S T U V W X Y Z
### Keywords
keyword:: one of
abstract arraykey as async break case catch class classname clone const continue default do
echo else elseif enum extends final finally for foreach function if implements
instanceof insteadof interface mixed namespace new newtype noreturn num parent private
protected public require require_once return self shape static switch throw trait try
tuple type use while yield
### Literals
#### General
literal::
boolean-literal
integer-literal
floating-literal
string-literal
null-literal
#### Boolean Literals
boolean-literal::
true
false
#### Integer Literals
integer-literal::
decimal-literal
octal-literal
hexadecimal-literal
binary-literal
decimal-literal::
nonzero-digit
decimal-literal digit
octal-literal::
0
octal-literal octal-digit
hexadecimal-literal::
hexadecimal-prefix hexadecimal-digit
hexadecimal-literal hexadecimal-digit
hexadecimal-prefix:: one of
0x 0X
binary-literal::
binary-prefix binary-digit
binary-literal binary-digit
binary-prefix:: one of
0b 0B
digit:: one of
0 1 2 3 4 5 6 7 8 9
nonzero-digit:: one of
1 2 3 4 5 6 7 8 9
octal-digit:: one of
0 1 2 3 4 5 6 7
hexadecimal-digit:: one of
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F
binary-digit:: one of
0 1
#### Floating-Point Literals
floating-literal::
fractional-literal exponent-partopt
digit-sequence exponent-part
fractional-literal::
digit-sequenceopt . digit-sequence
digit-sequence .
exponent-part::
e signopt digit-sequence
E signopt digit-sequence
sign:: one of
+ -
digit-sequence::
digit
digit-sequence digit
#### String Literals
string-literal::
single-quoted-string-literal
double-quoted-string-literal
heredoc-string-literal
nowdoc-string-literal
single-quoted-string-literal::
bopt ' sq-char-sequenceopt '
sq-char-sequence::
sq-char
sq-char-sequence sq-char
sq-char::
sq-escape-sequence
\opt any member of the source character set except single-quote (') or backslash (\)
sq-escape-sequence:: one of
\' \\
double-quoted-string-literal::
bopt " dq-char-sequenceopt "
dq-char-sequence::
dq-char
dq-char-sequence dq-char
dq-char::
dq-escape-sequence
any member of the source character set except double-quote (") or backslash (\)
\ any member of the source character set except "\$efnrtvxX or
octal-digit
dq-escape-sequence::
dq-simple-escape-sequence
dq-octal-escape-sequence
dq-hexadecimal-escape-sequence
dq-simple-escape-sequence:: one of
\" \\ \$ \e \f \n \r \t \v
dq-octal-escape-sequence::
\ octal-digit
\ octal-digit octal-digit
\ octal-digit octal-digit octal-digit
dq-hexadecimal-escape-sequence::
\x hexadecimal-digit hexadecimal-digitopt
\X hexadecimal-digit hexadecimal-digitopt
heredoc-string-literal::
<<< hd-start-identifier new-line hd-char-sequenceopt new-line hd-end-identifier ;opt new-line
hd-start-identifier::
name
hd-end-identifier::
name
hd-char-sequence::
hd-char
hd-char-sequence hd-char
hd-char::
hd-escape-sequence
any member of the source character set except backslash (\)
\ any member of the source character set except \$efnrtvxX or
octal-digit
hd-escape-sequence::
hd-simple-escape-sequence
dq-octal-escape-sequence
dq-hexadecimal-escape-sequence
hd-simple-escape-sequence:: one of
\\ \$ \e \f \n \r \t \v
nowdoc-string-literal::
<<< ' hd-start-identifier ' new-line hd-char-sequenceopt new-line hd-end-identifier ;opt new-line
#### The Null Literal
null-literal::
null
### Operators and Punctuators
operator-or-punctuator:: one of
[ ] ( ) { } . -> ++ -- ** * + - ~ !
$ / % << >> < > <= >= == === != !== ^ |
& && || ? ?? : ; = **= *= /= %= += -= .= <<=
>>= &= ^= |= , @ :: => ==> ?-> \ ... |> $$
## Syntactic Grammar
### Program Structure
script: <?hh // strict declaration-listopt declaration-list: declaration declaration-list declaration declaration: inclusion-directive enum-declaration function-definition class-declaration interface-declaration trait-declaration namespace-definition namespace-use-declaration alias-declaration### Types #### General
type-specifier: bool int float num string arraykey void resource alias-type-specifier vector-like-array-type-specifier map-like-array-type-specifier enum-specifier class-interface-trait-specifier tuple-type-specifier shape-specifier closure-type-specifier nullable-type-specifier generic-type-parameter-name this classname-type-specifier type-constant-type-name alias-type-specifier: qualified-name enum-specifier: qualified-name class-interface-trait-specifier: qualified-name generic-type-argument-listopt type-specifier-list: type-specifiers ,opt type-specifiers: type-specifier type-specifiers , type-specifier type-constraint: as type-specifier type-constant-type-name: name :: name self :: name this :: name type-constant-type-name :: name#### Array Types
vector-like-array-type-specifier: array < array-value-type-specifier > map-like-array-type-specifier: array < array-value-type-specifier , array-value-type-specifier > array-value-type-specifier: type-specifier array-key-type-specifier: type-specifier#### Tuple Types
tuple-type-specifier: ( type-specifier , type-specifier-list )#### Shape Types
shape-specifier: shape ( field-specifier-listopt ) field-specifier-list: field-specifier field-specifier-list , field-specifier field-specifier: single-quoted-string-literal => type-specifier qualified-name => type-specifier scope-resolution-expression => type-specifier#### Closure Types
closure-type-specifier: ( function ( type-specifier-listopt ) : type-specifier )#### Nullable Types
nullable-type-specifier: ? type-specifier mixed#### The Classname Type
classname-type-specifier: classname < qualified-name generic-type-argument-listopt >#### Type Aliases
alias-declaration: attribute-specificationopt type name generic-type-parameter-listopt = type-specifier ; attribute-specificationopt newtype name generic-type-parameter-listopt type-constraintopt = type-specifier ;### Variables
function-static-declaration:
static static-declarator-list ;
static-declarator-list:
static-declarator
static-declarator-list , static-declarator
static-declarator:
variable-name function-static-initializeropt
function-static-initializer:
= const-expression
### Expressions
#### Primary Expressions
primary-expression:
variable-name
qualified-name
literal
const-expression
intrinsic
collection-literal
tuple-literal
shape-literal
anonymous-function-creation-expression
awaitable-creation-expression
( expression )
$this
$$
intrinsic:
array-intrinsic
echo-intrinsic
exit-intrinsic
invariant-intrinsic
list-intrinsic
array-intrinsic:
array ( array-initializeropt )
echo-intrinsic:
echo expression
echo ( expression )
echo expression-list-two-or-more
expression-list-two-or-more:
expression , expression
expression-list-two-or-more , expression
exit-intrinsic:
exit expressionopt
exit ( expressionopt )
invariant-intrinsic:
invariant ( condition , format )
invariant ( condition , format , values )
list-intrinsic:
list ( list-expression-listopt )
list-expression-list:
expression
,
list-expression-list , expressionopt
collection-literal:
non-key-collection-class-type { cl-initializer-list-without-keysopt }
key-collection-class-type { cl-initializer-list-with-keysopt }
pair-type { cl-element-value , cl-element-value }
non-key-collection-class-type:
qualified-name non-key-collection-class-type-hintopt
key-collection-class-type:
qualified-name key-collection-class-type-hintopt
non-key-collection-class-type-hint:
< type-specifier &rt;
key-collection-class-type-hint:
< type-specifier , type-specifier &rt;
pair-type:
qualified-name
cl-initializer-list-without-keys:
cl-element-value
cl-initializer-list-without-keys , cl-element-value
cl-initializer-list-with-keys:
cl-element-key => cl-element-value
cl-initializer-list-with-keys , cl-element-key => cl-element-value
cl-element-key:
expression
cl-element-value:
expression
tuple-literal:
tuple ( expression-list-one-or-more )
expression-list-one-or-more:
expression
expression-list-one-or-more , expression
shape-literal:
shape ( field-initializer-listopt )
field-initializer-list:
field-initializers ,opt
field-initializers:
field-initializer
field-initializers , field-initializer
field-initializer:
single-quoted-string-literal => expression
integer-literal => expression
qualified-name => expression
scope-resolution-expression => expression
anonymous-function-creation-expression:
asyncopt function ( anonymous-function-parameter-listopt ) anonymous-function-returnopt anonymous-function-use-clauseopt compound-statement
anonymous-function-parameter-list:
...
anonymous-function-parameter-declaration-list
anonymous-function-parameter-declaration-list ,
anonymous-function-parameter-declaration-list , ...
anonymous-function-parameter-declaration-list:
anonymous-function-parameter-declaration
anonymous-function-parameter-declaration-list , anonymous-function-parameter-declaration
anonymous-function-parameter-declaration:
attribute-specificationopt type-specifieropt variable-name default-argument-specifieropt
anonymous-function-return:
: return-type
anonymous-function-use-clause:
use ( use-variable-name-list ,opt )
use-variable-name-list:
variable-name
use-variable-name-list , variable-name
awaitable-creation-expression:
async { async-statement-listopt }
async-statement-list:
statement
async-statement-list statement
#### Postfix Operators
postfix-expression:
-expression
clone-expression
object-creation-expression
array-creation-expression
subscript-expression
function-call-expression
member-selection-expression
null-safe-member-selection-expression
postfix-increment-expression
postfix-decrement-expression
scope-resolution-expression
exponentiation-expression
clone-expression:
clone expression
object-creation-expression:
new class-type-designator ( argument-expression-listopt )
class-type-designator:
parent
self
static
member-selection-expression
null-safe-member-selection-expression
qualified-name
scope-resolution-expression
subscript-expression
variable-name
array-creation-expression:
array ( array-initializeropt )
[ array-initializeropt ]
array-initializer:
array-initializer-list ,opt
array-initializer-list:
array-element-initializer
array-element-initializer , array-initializer-list
array-element-initializer:
element-value
element-key => element-value
element-key:
expression
element-value
expression
subscript-expression:
postfix-expression [ expressionopt ]
postfix-expression { expressionopt } [Deprecated form]
function-call-expression:
postfix-expression ( argument-expression-listopt )
argument-expression-list:
argument-expressions ,opt
argument-expressions:
expression
argument-expressions , expression
member-selection-expression:
postfix-expression -> name
postfix-expression -> variable-name
null-safe-member-selection-expression:
postfix-expression ?-> name
postfix-expression ?-> variable-name
postfix-increment-expression:
unary-expression ++
postfix-decrement-expression:
unary-expression --
scope-resolution-expression:
scope-resolution-qualifier :: name
scope-resolution-qualifier :: variable-name
scope-resolution-qualifier :: class
scope-resolution-qualifier:
qualified-name
variable-name
self
parent
static
exponentiation-expression:
expression ** expression
#### Unary Operators
unary-expression:
postfix-expression
prefix-increment-expression
prefix-decrement-expression
unary-op-expression
error-control-expression
cast-expression
await-expression
prefix-increment-expression:
++ unary-expression
prefix-decrement-expression:
-- unary-expression
unary-op-expression:
unary-operator cast-expression
unary-operator: one of
+ - ! ~
error-control-expression:
@ expression
cast-expression:
( cast-type ) unary-expression
cast-type: one of
bool int float string
await-expression:
await expression
#### instanceof Operator
instanceof-expression:
unary-expression
instanceof-subject instanceof instanceof-type-designator
instanceof-subject:
expression
instanceof-type-designator:
qualified-name
variable-name
#### Multiplicative Operators
multiplicative-expression:
instanceof-expression
multiplicative-expression * instanceof-expression
multiplicative-expression / instanceof-expression
multiplicative-expression % instanceof-expression
#### Additive Operators
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
additive-expression . multiplicative-expression
#### Bitwise Shift Operators
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
#### Relational Operators
relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression
#### Equality Operators
equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
equality-expression === relational-expression
equality-expression !== relational-expression
#### Bitwise Logical Operators
bitwise-AND-expression:
equality-expression
bit-wise-AND-expression & equality-expression
bitwise-exc-OR-expression:
bitwise-AND-expression
bitwise-exc-OR-expression ^ bitwise-AND-expression
bitwise-inc-OR-expression:
bitwise-exc-OR-expression
bitwise-inc-OR-expression | bitwise-exc-OR-expression
#### Logical Operators
logical-AND-expression:
bitwise-inc-OR-expression
logical-AND-expression && bitwise-inc-OR-expression
logical-inc-OR-expression:
logical-AND-expression
logical-inc-OR-expression || logical-AND-expression
#### Conditional Operator
conditional-expression:
logical-inc-OR-expression
logical-inc-OR-expression ? expressionopt : conditional-expression
#### Pipe Operator
piped-expression:
coalesce-expression
piped-expression |> coalesce-expression
#### Lambda Expressions
lambda-expression: piped-expression asyncopt lambda-function-signature ==> lambda-body lambda-function-signature: variable-name ( anonymous-function-parameter-declaration-listopt ) anonymous-function-returnopt lambda-body: expression compound-statement#### Assignment Operators
assignment-expression:
lambda-expression
simple-assignment-expression
compound-assignment-expression
simple-assignment-expression:
unary-expression = assignment-expression
byref-assignment-expression:
unary-expression = & assignment-expression
compound-assignment-expression:
unary-expression compound-assignment-operator assignment-expression
compound-assignment-operator: one of
**= *= /= %= += -= .= <<= >>= &= ^= |=
#### yield Operator
expression:
assignment-expression
yield array-element-initializer
#### Constant Expressions
constant-expression:
array-creation-expression
collection-literal
tuple-literal
shape-literal
const-expression
const-expression:
expression
### Statements
#### General
statement:
function-static-declaration
compound-statement
labeled-statement
expression-statement
selection-statement
iteration-statement
jump-statement
try-statement
#### Compound Statements
compound-statement:
{ statement-listopt }
statement-list:
statement
statement-list statement
#### Labeled Statements
labeled-statement:
case-label
default-label
case-label:
case expression : statement
default-label:
default : statement
#### Expression Statements
expression-statement:
expressionopt ;
selection-statement:
if-statement
switch-statement
if-statement:
if ( expression ) statement elseif-clauses-opt else-clause-opt
elseif-clauses:
elseif-clause
elseif-clauses elseif-clause
elseif-clause:
elseif ( expression ) statement
else-clause:
else statement
switch-statement:
switch ( expression ) compound-statement
#### Iteration Statements
iteration-statement:
while-statement
do-statement
for-statement
foreach-statement
while-statement:
while ( expression ) statement
do-statement:
do statement while ( expression ) ;
for-statement:
for ( for-initializeropt ; for-controlopt ; for-end-of-loopopt ) statement
for-initializer:
for-expression-group
for-control:
for-expression-group
for-end-of-loop:
for-expression-group
for-expression-group:
expression
for-expression-group , expression
foreach-statement:
foreach ( foreach-collection-name as foreach-keyopt foreach-value ) statement
foreach ( foreach-collection-name await as foreach-keyopt foreach-value ) statement
foreach-collection-name:
expression
foreach-key:
expression =>
foreach-value:
expression
list-intrinsic
#### Jump Statements
jump-statement:
continue-statement
break-statement
return-statement
throw-statement
continue-statement:
continue ;
break-statement:
break ;
return-statement:
return expressionopt ;
throw-statement:
throw expression ;
#### The try Statement
try-statement:
try compound-statement catch-clauses
try compound-statement finally-clause
try compound-statement catch-clauses finally-clause
catch-clauses:
catch-clause
catch-clauses catch-clause
catch-clause:
catch ( type-specifier variable-name ) compound-statement
finally-clause:
finally compound-statement
### Script Inclusion
inclusion-directive:
require-multiple-directive
require-once-directive
require-multiple-directive:
require include-filename ;
include-filename:
expression
require-once-directive:
require_once include-filename ;
### Enums
enum-declaration:
enum name enum-base type-constraintopt { enumerator-listopt }
enum-base:
: int
: string
enumerator-list:
enumerator
enumerator-list enumerator
enumerator:
enumerator-constant = constant-expression ;
enumerator-constant:
name
### Generic Types, Methods and Functions
generic-type-parameter-list:
< generic-type-parameters ,opt >
generic-type-parameters:
generic-type-parameter
generic-type-parameters , generic-type-parameter
generic-type-parameter:
generic-type-parameter-varianceopt generic-type-parameter-name type-constraintopt
generic-type-parameter-name:
name
generic-type-parameter-variance:
+
-
generic-type-argument-list:
< generic-type-arguments ,opt >
generic-type-arguments:
generic-type-argument
generic-type-arguments , generic-type-argument
generic-type-argument:
type-specifier
name
### Functions
function-definition:
attribute-specificationopt function-definition-no-attribute
function-definition-no-attribute:
function-definition-header compound-statement
function-definition-header:
asyncopt function name generic-type-parameter-listopt ( parameter-listopt ) : return-type
parameter-list:
...
parameter-declaration-list ,opt
parameter-declaration-list , ...
parameter-declaration-list:
parameter-declaration
parameter-declaration-list , parameter-declaration
parameter-declaration:
attribute-specificationopt type-specifier variable-name default-argument-specifieropt
default-argument-specifier:
= const-expression
return-type:
type-specifier
noreturn
### Classes
class-declaration:
attribute-specificationopt class-modifieropt class name generic-type-parameter-listopt class-base-clauseopt
class-interface-clauseopt { trait-use-clausesopt class-member-declarationsopt }
class-modifier:
abstract
final
abstract final
class-base-clause:
extends qualified-name generic-type-argument-listopt
class-interface-clause:
implements qualified-name generic-type-argument-listopt
class-interface-clause , qualified-name generic-type-argument-listopt
class-member-declarations:
class-member-declaration
class-member-declarations class-member-declaration
class-member-declaration:
const-declaration
property-declaration
method-declaration
constructor-declaration
destructor-declaration
type-constant-declaration
const-declaration:
abstractopt const type-specifieropt constant-declarator-list ;
constant-declarator-list:
constant-declarator
constant-declarator-list , constant-declarator
constant-declarator:
name constant-initializeropt
constant-initializer:
= const-expression
property-declaration:
property-modifier type-specifier property-declarator-list ;
property-declarator-list:
property-declarator
property-declarator-list , property-declarator
property-declarator:
variable-name property-initializeropt
property-modifier:
visibility-modifier static-modifieropt
static-modifier visibility-modifier
visibility-modifier:
public
protected
private
static-modifier:
static
property-initializer:
= expression
method-declaration:
attribute-specificationopt method-modifiers function-definition-no-attribute
attribute-specificationopt method-modifiers function-definition-header ;
method-modifiers:
method-modifier
method-modifiers method-modifier
method-modifier:
visibility-modifier
static-modifier
abstract
final
constructor-declaration:
attribute-specificationopt constructor-modifiers function __construct (
constructor-parameter-declaration-listopt ) void-returnopt compound-statement
constructor-parameter-declaration-list:
constructor-parameter-declaration
constructor-parameter-declaration-list , constructor-parameter-declaration
constructor-parameter-declaration:
visibility-modifieropt type-specifier variable-name default-argument-specifieropt
constructor-modifiers:
constructor-modifier
constructor-modifiers constructor-modifier
constructor-modifier:
visibility-modifier
abstract
final
destructor-declaration:
attribute-specificationopt visibility-modifier function __destruct ( ) void-returnopt compound-statement
void-return:
: void
type-constant-declaration:
abstract-type-constant-declaration
concrete-type-constant-declaration
abstract-type-constant-declaration:
abstract const type name type-constraintopt ;
concrete-type-constant-declaration:
const type name type-constraintopt = type-specifier ;
### Interfaces
interface-declaration:
attribute-specificationopt interface name generic-type-parameter-listopt interface-base-clauseopt {
interface-member-declarationsopt }
interface-base-clause:
extends qualified-name generic-type-argument-listopt
interface-base-clause , qualified-name generic-type-argument-listopt
interface-member-declarations:
interface-member-declaration
interface-member-declarations interface-member-declaration
interface-member-declaration:
require-extends-clause
const-declaration
method-declaration
type-constant-declaration
### Traits
trait-declaration:
attribute-specificationopt trait name generic-type-parameter-listopt class-interface-clauseopt {
trait-use-clausesopt trait-member-declarationsopt }
trait-use-clauses:
trait-use-clause
trait-use-clauses trait-use-clause
trait-use-clause:
use trait-name-list ;
trait-name-list:
qualified-name generic-type-argument-listopt
trait-name-list , qualified-name generic-type-argument-listopt
trait-member-declarations:
trait-member-declaration
trait-member-declarations trait-member-declaration
trait-member-declaration:
require-extends-clause
require-implements-clause
property-declaration
method-declaration
constructor-declaration
destructor-declaration
require-extends-clause:
require extends qualified-name ;
require-implements-clause:
require implements qualified-name ;
### Namespaces
namespace-definition:
namespace namespace-name ;
namespace namespace-nameopt { declaration-listopt }
namespace-use-declaration:
use namespace-use-kindopt namespace-use-clauses ;
use namespace-use-kind namespace-name-as-a-prefix { namespace-use-clauses } ;
use namespace-name-as-a-prefix { namespace-use-kind-clauses } ;
namespace-use-clauses:
namespace-use-clause
namespace-use-clauses , namespace-use-clause
namespace-use-clause:
qualified-name namespace-aliasing-clauseopt
namespace-use-kind-clauses:
namespace-use-kind-clause
namespace-use-kind-clauses , namespace-use-kind-clause
namespace-use-kind-clause:
namespace-use-kindopt qualified-name namespace-aliasing-clauseopt
namespace-aliasing-clause:
as name
namespace-use-kind:
function
const
namespace-name:
name
namespace-name \ name
namespace-name-as-a-prefix:
\
\opt namespace-name \
namespace \
namespace \ namespace-name \
qualified-name:
namespace-name-as-a-prefixopt name
### Attributes
attribute-specification: << attribute-list >> attribute-list: attribute attribute-list , attribute attribute: attribute-name attribute-value-listopt attribute-name: name attribute-value-list: ( attribute-valuesopt ) attribute-values attribute-value attribute-values , attribute-value attribute-value: expression================================================ FILE: spec/23-differences-from-php.md ================================================ # Differences from PHP ## General This annex identifies the PHP features that are either not supported in Hack or that have different semantics. ## Program Start-Up Hack's strict mode does not allow access to any of the following: `$argc`, `$argv`, `$_COOKIE`,` $_ENV`, `$_FILES`, `$_GET`, `$GLOBALS`, `$_POST`, `$_REQUEST`, `$_SERVER`, or `$_SESSION`. ## Constants Constants cannot be defined at the top level. Regarding `define()`'s names, lookup doesn’t work like in PHP. In Hack, have to use function `constant('name')` to refer to a defined name. `__CLASS__` cannot be used outside a class or trait. `__TRAIT__` cannot be used outside a trait. ## Variables Constants are not supported except in classes and interfaces. Global variables are not supported. Superglobals don’t exist. ## Conversions Unlike PHP, Hack's conversion rules are very strict. As such, they may invalidate existing PHP code in the contexts of assignment, argument passing, and value returning. Specifically: * No non-`bool` type can be converted implicitly to `bool`. All other conversions must be explicit. * No non-`int` type can be converted implicitly to `int`. All other conversions must be explicit. * No non-`float` type can be converted implicitly to `float`. All other conversions must be explicit. * No non-`string` type can be converted implicitly to `string`. All other conversions must be explicit. * For arrays of different types, no implicit conversions exist. There are no explicit conversions to any array type. * An object type can be converted implicitly to any object type from which the first object type is directly or indirectly derived. There are no other implicit or explicit conversions. * An object type can be converted implicitly to any interface type that object type implements directly or indirectly. An interface type can be converted implicitly to any interface type from which the first interface type is directly or indirectly derived. There are no other implicit or explicit conversions. * No non-`resource` type can be converted implicitly to `resource`. No explicit conversions exist. ## Lexical Structure ### Comments Hack treats comments of the forms `// strict` and `// FALLTHROUGH` in a special way. ### Names In Hack, function and method names are case-sensitive. ### Keywords The following PHP identifiers are keywords in Hack: `arraykey`, `async`, `enum`, `mixed`, `newtype`, `num`, `parent`, `self`, `shape`, `tuple`, and `type`. ## Expressions ### Primary Expressions #### General The name of a function cannot be used as an expression without the function-call operator. Unlike in PHP, that name is not treated as a string containing that function's name. #### Intrinsics The following intrinsics are not supported: `empty`, `eval`, `die`, `isset`, `print`, and `unset`. For the intrinsic `list`, the target variables must be defined; the right-hand operand cannot be a map-like array; there must not be fewer element candidates in the source than there are target variables; and only the right-most variable can be omitted. Lists of lists are not permitted. #### Anonymous Function-Creation The `&` byRef notation is not permitted on the function's return type nor in the use clause. ### Postfix Operators #### The `new` Operator A call to a constructor without any arguments requires the function-call parentheses. The *class-type-designator* cannot be a string containing a class name; it must be the class name itself. #### Array Creation Operator The `&` byRef notation is not permitted. With the distinction between vector-like arrays and map-like arrays, either all of the initializers must contain keys or none of them can have keys. #### Function call operator The caller must pass an argument for each parameter not having a default value. Each argument passed is type-checked against the corresponding parameter. Variable functions are not permitted; however, the same thing can be achieved via the library function `fun`. #### Member-Selection Operator The member name must be hard-coded; it cannot be expressed as a string. This operator cannot be used to access a static method via an instance. #### Postfix Increment and Decrement Operators The operand must have arithmetic type. #### Exponentiation Operator Both operands must have arithmetic type. ### Unary Operators #### Prefix Increment and Decrement Operators The operand must have arithmetic type. #### Unary Arithmetic Operators The operand must have arithmetic type. #### Shell Command Operator This operator is not supported. #### Cast Operator Hack does not allow casts to `array`, `binary`, `boolean`, `double`, `integer`, `object`, `real`, or `unset`. #### Variable-Name Creation Operator PHP allows variables to reference each other by means of a "variable variable". There are two syntaxes in PHP; if `$y` is equal to the string `"x"` then `$$y` and `${$y}` are both aliases for `$x`. This operator is not supported. ### `instanceof` Operator The right-hand operand cannot be a string. ### Multiplicative Operators The operands of the `*` and `/` operators must have arithmetic type. The operands of the `%` operator must have integer type. ### Bitwise Shift Operators Both operands must have type `int`; there is no implicit conversion. ### Bitwise `AND` Operator Both operands must have type `int`; there is no implicit conversion. ### Bitwise Exclusive `OR` Operator Both operands must have type `int`; there is no implicit conversion. ### Bitwise Inclusive `OR` Operator Both operands must have type `int`; there is no implicit conversion. ### Assignment Operators #### byRef Assignment This is not supported. ### Logical `AND`, `OR`, `XOR` Operators (Alternate Forms) The `and`, `xor`, and `or` alternate forms are not supported. ### String Literals PHP allows the syntax `"${ expression }"` in a double-quoted string literal, where the expression can be the name of a variable, or any expression which evaluates to a string naming a variable. This is an invalid string interpolation syntax in Hack. ## Statements ### General Statements cannot exist at the top level of a script. ### Labeled Statements There are no named labels or `goto` statement. ### The `if` Statement The alternate `: endif;` syntax is not supported. ### The `switch` Statement The alternate `: endswitch;` syntax is not supported. Unlike PHP, in Hack, each label expression's type must be a subtype of the switch expression type. For example, `switch(10)` won’t work with case `$a < $b:`. ### The `while` Statement The alternate `: endwhile;` syntax is not supported. ### The `for` Statement The alternate `: endfor;` syntax is not supported. ### The `foreach` Statement The alternate` : endforeach;` syntax is not supported. Unlike PHP, given `foreach ($colors as $index => $color)`, in Hack, the names `$index` and `$color` are not in scope outside the `foreach` body. ### The `goto` Statement This statement is not supported. ### The `continue` Statement `continue n;` is not supported. In PHP, `continue;` inside a `switch` statement is equivalent to` break;`. Hack does not emulate this. ### The `break` Statement `break n;` is not supported. ### The `return` Statement This can't appear in a finally block. This can’t be used to terminate a require file. ### The declare Statement This is not supported. ## Script Inclusion `include` and `include_once` are not supported. `require` and `require_once` can be used only at the top level. They are not operators, so they do not produce a value. ## Functions Nested/conditional functions are not supported; except for anonymous functions, functions can only be defined at the top level. Passing and/or return by reference is not supported. The `array` and `callable` type hints are not supported. Every parameter must have a type. If any parameter has a default argument value, then all parameters following it must also have one. An empty parameter list means, "no arguments can be passed". A return type is required and a return type of `void` won’t let a value be returned. A non-`void` return type requires a return value of some subtype. ## Classes ### Class Members All members except `const` must have a visibility modifier; there is no defaulting. ### Dynamic Members Dynamic properties are not supported. Dynamic methods are supported, but `__call` cannot be called directly. ### Properties A type specifier is needed. The `var` modifier is not supported. All properties of non-nullable type must be initialized explicitly either by a *property-initializer* or by the constructor. Properties of nullable type that are not explicitly initialized take on the value null. (as with PHP). ### Methods Hack requires parameter and return-type type specifiers. ### Constructors The deprecated form of constructor name (using the name of the class) is not supported. ### Methods with Special Semantics #### General Hack requires parameter and return-type type specifiers. #### Method `__call` It works, but it can't be called directly. #### Method `__get` This method does not exist, as dynamic properties are not supported. #### Method `__invoke` Using an instance like a function call is not supported. #### Method __isset This method does not exist, as dynamic properties are not supported. #### Method __set This method does not exist, as dynamic properties are not supported. #### Method __set_state This is not useful, as the intrinsic `eval` is not supported. #### Method __unset This method does not exist, as dynamic properties are not supported. ### Predefined Classes #### Class Closure This type does not exist. ## Interfaces ### Interface Members All members except `const` must have a visibility modifier; there is no defaulting. ### Methods Hack requires parameter and return-type type specifiers. ### Predefined Interfaces The interfaces `ArrayAccess`, `Iterator`, `IteratorAggregate`, and `Traversable` are now generic interfaces. ## Traits ### Trait Declarations Hack doesn’t support aliases and selection in a trait. ## Namespaces ### Namespace Use Declarations Can’t have a use clause, with or without an “as” at other than the top level of a script. ================================================ FILE: spec/24-bibliography.md ================================================ # Bibliography The following documents are useful references for implementers and users of this specification: IEC 60559:1989, *Binary floating-point arithmetic for microprocessor systems* (previously designated IEC 559:1989). (This standard is widely known by its U.S. national designation, ANSI/IEEE Standard 754-1985, IEEE Standard for Binary Floating-Point Arithmetic.) The Unicode Consortium. *The Unicode Standard, Version 5.0*, [www.Unicode.org](http://www.Unicode.org)). ================================================ FILE: spec/hack-spec-draft.md ================================================ # Specification for PHP Facebook has dedicated all copyright to this specification to the public domain worldwide under the CC0 Public Domain Dedication located at
script: script-section script script-section script-section: textopt <?php statement-listopt ?>opt textopt text: arbitrary text not containing the sequence <?phpAll of the sections in a script are treated as though they belonged to one continuous section, except that any intervening text is treated as though it were a string literal given to the intrinsic `echo` ([§§](#echo)). A script can import another script via a script inclusion operator ([§§](#script-inclusion-operators)). *statement-list* is defined in [§§](#compound-statements). The top level of a script is simply referred to as the *top level*. # # Program Start-Up A program begins execution at the start of a script ([§§](#program-structure)) designated in some unspecified manner. This script is called the *start-up script*. Once a program is executing, it has access to certain environmental information ([§§](#predefined-variables)), as follows: - The number of *command-line arguments*, via the predefined variable `$argc`. - A series of one or more command-line arguments as strings, via the predefined variable `$argv`. - A series of *environment variable* names and their definitions. When a top level ([§§](#program-structure)) is the main entry point for a script, it gets the global variable environment. When a top level is invoked via `include/require` ([§§](#general-16)), it inherits the variable environment of its caller. Thus, when looking at one top level in isolation, it's not possible to tell statically whether it will have the global variable environment or some local variable environment. It depends on how the pseudo-main is invoked and it depends on the runtime state of the program when it's invoked. # # Program Termination A program may terminate normally in the following ways: - Execution reaches the end of the start-up script ([§§](#program-start-up)). - A `return` statement ([§§](#the-return-statement)) in the start-up script is executed. - The intrinsic `exit` ([§§](#exitdie)) is called explicitly. The behavior of the first two cases is equivalent to corresponding calls to exit. A program may terminate abnormally under various circumstances, such as the detection of an uncaught exception, or the lack of memory or other critical resource. If execution reaches the end of the start-up script via a fatal error, or via an uncaught exception and there is no uncaught exception handler registered by `set_exception_handler`, that is equivalent to `exit(255)`. If execution reaches the end of the start-up script via an uncaught exception and an uncaught exception handler was registered by `set_exception_handler`, that is equivalent to exit(0). It is unspecified whether object destructors ([§§](#destructors)) are run. In all other cases, the behavior is unspecified. # # The Memory Model ## # General This subclause and those immediately following it describe the abstract memory model used by PHP for storing variables. A conforming implementation may use whatever approach is desired as long as from any testable viewpoint it appears to behave as if it follows the abstract model. The abstract model makes no explicit or implied restrictions or claims about performance, memory consumption, and machine resource usage. The abstract model presented here defines three kinds of abstract memory locations: - A *value storage location* (VStore) is used to represent a program value, and is created by the Engine as needed. A VStore can contain a scalar value such as an integer or a Boolean, or it can contain a handle pointing to an HStore (see below). - A *variable slot* (VSlot) is used to represent a variable named by the programmer in the source code, such as a local variable, an array element, an instance property of an object, or a static property of a class. A VSlot comes into being based on explicit usage of a variable in the source code. A VSlot contains a pointer to a VStore. - A *heap storage location* (HStore) is used to represent the contents of any non-scalar value, and is created by the Engine as needed. Each existing variable has its own VSlot, which at any time contains a pointer to a VStore. A VSlot cannot contain a null pointer. A VSlot can be changed to point to different VStores over time. Multiple VSlots may simultaneously point to the same VStore. When a new VSlot is created, a new VStore is also created and the VSlot is initially set to point to the new VStore. A VStore can be changed to contain different scalar values and handles over time. Multiple VStores may simultaneously contain handles that point to the same HStore. When a VStore is created it initially contains the scalar value NULL unless specified otherwise. In addition to containing a value, VStores also carry a *type tag* that indicates the type ([§§](#types)) of the VStore’s value. A VStore’s type tag can be changed over time. At any given time a VStore’s type tag may be one of the following: `Null`, `Bool`, `Int`, `Float`, `Str`, `Arr`, `Arr-D` (see [§§](#deferred-array-copying)), `Obj`, or `Res`. An HStore represents the contents of a non-scalar value, and it may contain zero or more VSlots. At run time, the Engine may add new VSlots and it may remove and destroy existing VSlots as needed to support adding/removing array elements (for arrays) and to support adding/removing instance properties (for objects). HStores that represent the contents of arrays and objects have some unspecified way to identify and retrieve a contained VSlot using a dictionary scheme (such as having values with integer keys or case-sensitive string keys). Whether an HStore is a fixed-size during its whole lifetime or whether it can change size, is unspecified. Whether it allocates auxiliary chunks of memory or not, is unspecified. Whether it organizes it's contained VSlots in a linked list or some other manner is unspecified. An HStore’s VSlots (i.e., the VSlots contained within the HStore) point to VStores, and each VStore contains a scalar value or a handle to an HStore, and so on through arbitrary levels, allowing arbitrarily complex data structures to be represented. For example, a singly linked list might consist of a variable called `$root`, which is represented by a VSlot pointing to a VStore containing a handle to the first node. Each node is represented by an HStore that contains the data for that node in one or more VSlots, as well as a VSlot pointing to VStore containing a handle to the next node. Similarly, a binary tree might consist of a variable called `$root`, which is represented by a VSlot pointing to a VStore containing a handle to the root node. Each node is represented by an HStore that contains the data for that node in one or more VSlots, as well as a pair of VSlots pointing to VStores containing the handles to the left and right branch nodes. The leaves of the tree would be VStores or HStores, as needed. VSlots cannot contain pointers to VSlots or handles to HStores. VStores cannot contain pointers to VSlots or VStores. HStores cannot directly contain any pointers or handles to any abstract memory location; HStores can only directly contain VSlots. Here is an example demonstrating one possible arrangement of VSlots, VStores, and HStores:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]] | | V V [VStore Int 1] [VStore Int 3]In this picture the VSlot in the upper left corner represents the variable `$a`, and it points to a VStore that represents `$a`’s current value. This VStore contains a handle to an HStore which represents the contents of an object of type Point with two instance properties `$x` and `$y`. This HStore contains two VSlots representing instance properties `$x` and `$y`, and each of these VSlots points to a distinct VStore which contains an integer value. ***Implementation Notes:*** php.net’s implementation can be mapped roughly onto the abstract memory model as follows: `zval pointer => VSlot, zval => VStore, HashTable => HStore`, and `zend_object/zend_object_handlers => HStore`. Note, however, that the abstract memory model is not intended to exactly match the php.net implementation’s model, and for generality and simplicity there are some superficial differences between the two models. For most operations, the mapping between VSlots and VStores remains the same. Only the following program constructs can change a VSlot to point to different VStore, all of which are *byRef-aware* operations and all of which (except unset) use the & punctuator: - byRef assignment ([§§](#byref-assignment)) - byRef parameter declaration ([§§](#function-definitions)) - byRef function return ([§§](#the-return-statement), [§§](#function-definitions)) - byRef value in a foreach statement ([§§](#the-foreach-statement)) - byRef initializer for an array element ([§§](#array-creation-operator)) - byRef variable-use list in an anonymous function ([§§](#anonymous-function-creation)) - unset ([§§](#unset)) ## # Reclamation and Automatic Memory Management The Engine is required to manage the lifetimes of VStores and HStores using some form of automatic memory management. When dealing with VStores and HStores, the Engine is required to implement some form of automatic memory management. When a VStore or HStore is created, memory is allocated for it, and for an HStore that represents an object ([§§](#object-types)), its constructor ([§§](#constructors)) is invoked. Later, if a VStore or HStore becomes unreachable through any existing variable, they become eligible for reclamation to release the memory they occupy. The engine may reclaim a VStore or HStore at any time between when it becomes eligible for reclamation and when the script exits. Before reclaiming an HStore that represents an object ([§§](#object-types)), the Engine will invoke the object’s destructor ([§§](#constructors)) if one is defined. The Engine must reclaim each VSlot when the storage duration ([§§](#storage-duration)) of its corresponding variable ends, when the variable is explicitly unset by the programmer, or when the script exits, whichever comes first. In the case where a VSlot is contained within an HStore (i.e. an array element or an object instance property), the engine must immediate reclaim the VSlot when it is explicitly unset by the programmer, when the containing HStore is reclaimed, or when the script exits, whichever comes first. The precise form of automatic memory management used by the Engine is unspecified, which means that the time and order of the reclamation of VStores and HStores is unspecified. A VStore’s refcount is defined as the number of unreclaimed VSlots that point to the VStore. Because the precise form of automatic memory management is not specified, a VStore’s refcount at a given time may differ between conforming implementations due to VSlots, VStores, and HStores being reclaimed at different times. Despite the use of the term refcount, conforming implementations are not required to use a reference counting-based implementation for automatic memory management. **(dead)**: In some pictures, storage-location boxes are shown as (dead). For a VStore or an HStore this indicates that the VStore or HStore is no longer reachable through any variable and is eligible for reclamation. For a VSlot, this indicates that the VSlot has been reclaimed or, in the case of a VSlot contained with an HStore, that the containing HStore has been reclaimed or is eligible for reclamation. ## # Assignment ### # General This subclause and those immediately following it describe the abstract model’s implementation of *value assignment* and *byRef assignment*. Value assignment of non-array types to local variables is described first, followed by byRef assignment with local variables, followed by value assignment of array types to local variables, and ending with value assignment with complex left-hand side expressions, and byRef assignment with complex expressions on the left- or right-hand side. Value assignment and byRef assignment are core to the PHP language, and many other operations in this specification are described in terms of value assignment and byRef assignment. ### # Value Assignment of Scalar Types to a Local Variable Value assignment is the primary means by which the programmer can create local variables. If a local variable appears on the left-hand side of value assignment does not exist, the engine will bring a new local variable into existence and create a VSlot and initial VStore for storing the local variable’s value. Consider the following example of value assignment ([§§](#simple-assignment)) of scalar values to local variables: ``` $a = 123; $b = false; ```
[VSlot $a *]-->[VStore Int 123] [VSlot $b *]-->[VStore Bool false]Variable `$a` comes into existence and is represented by a newly created VSlot pointing to a newly created VStore. Then the integer value 123 is written to the VStore. Next, `$b` comes into existence represented by a VSlot and corresponding VStore, and the Boolean value false is written to the VStore. Next consider the value assignment `$b = $a`:
[VSlot $a *]-->[VStore Int 123] [VSlot $b *]-->[VStore Int 123 (Bool false was overwritten)]The integer value 123 is read from `$a`’s VStore and is written into `$b`’s VStore, overwriting its previous contents. As we can see, the two variables are completely self-contained; each has its own VStore containing a separate copy of the integer value 123. Value assignment reads the contents of one VStore and overwrites the contents of the other VStore, but the relationship of VSlots to VStores remains unchanged. Changing the value of `$b` has no effect on `$a`, and vice versa. Using literals or arbitrarily complex expressions on the right hand side of value assignment value works the same as it does for variables, except that the literals or expressions don’t have their own VSlots or VStores. The scalar value or handle produced by the literal or expression is written into the VStore of the left hand side, overwriting its previous contents. ***Implementation Notes:*** For simplicity, the abstract model’s definition of value assignment never changes the mapping from VSlots to VStores. This aspect of the abstract model is superficially different from the php.net implementation’s model, which in some cases will set two variable slots to point to the same zval when performing value assignment. Despite this superficial difference, php.net’s implementation produces the same observable behavior as the abstract model presented here. To illustrate the semantics of value assignment further, consider `++$b`:
[VSlot $a *]-->[VStore Int 123] [VSlot $b *]-->[VStore Int 124 (123 was overwritten)]Now consider `$a = 99`:
[VSlot $a *]-->[VStore Int 99 (123 was overwritten)] [VSlot $b *]-->[VStore Int 124]In both of these examples, one variable’s value is changed without affecting the other variable’s value. While the above examples only demonstrate value assignment for integer and Boolean values, the same mechanics apply for all scalar types. Note that strings are also considered scalar values for the purposes of the abstract memory model. Unlike non-scalar types which are represented using a VStore pointing to an HStore containing the non-scalar value’s contents, the abstract model assumes that a string’s entire contents (i.e., the string’s characters and its length) can be stored in a VStore and that value assignment for a string eagerly copies a string’s entire contents to the VStore being written to. Consider the following example: ``` $a = 'gg'; $b = $a; ```
[VSlot $a *]-->[VStore Str 'gg'] [VSlot $b *]-->[VStore Str 'gg']`$a`’s string value and `$b`’s string values are distinct from each other, and mutating `$a`’s string will not affect `$b`. Consider `++$b`, for example:
[VSlot $a *]-->[VStore Str 'gg'] [VSlot $b *]-->[VStore Str 'gh']***Implementation Notes:*** For simplicity, the abstract model represents a string as a scalar value that can be entirely contained within VStore. This aspect of the abstract model is superficially different from the php.net implementation’s model, where a zval points to a separate buffer in memory containing a string’s characters and in the common case multiple slots point to the same zval that holds the string. Despite this superficial difference, php.net’s implementation produces the same observable behavior (excluding performance and resource consumption) as the abstract model presented here. Because a string’s content can be arbitrarily large, copying a string’s entire contents for value assignment can be expensive. In practice an application written in PHP may rely on value assignment of strings being relatively inexpensive (in order to deliver acceptable performance), and as such it is common for an implementation to use a deferred copy mechanism to reduce the cost of value assignment for strings. Deferred copy mechanisms work by not copying a string during value assignment and instead allowing multiple variables to share the string’s contents indefinitely until a mutating operation (such as the increment operator) is about to be executed on the string, at which time some or all of the string’s contents are copied. A conforming implementation may choose to defer copying a string’s contents for value assignment so long as it has no observable effect on behavior from any testable viewpoint (excluding performance and resource consumption). ### # Value Assignment of Object and Resource Types to a Local Variable To demonstrate value assignment of objects to local variables, consider the case in which we have a Point class that supports a two-dimensional Cartesian system. An instance of Point contains two instance properties, `$x` and `$y`, that store the x- and y-coordinates, respectively. A constructor call ([§§](#constructors)) of the form `Point(x, y)` used with operator `new` ([§§](#the-new-operator)) creates a new point at the given location, and a method call of the form `move(newX, newY)` moves a `Point` to the new location. With the `Point` class, let us consider the value assignment `$a = new Point(1, 3)`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]] | | V V [VStore Int 1] [VStore Int 3]Variable `$a` is given its own VSlot, which points to a VStore that contains a handle pointing to an HStore allocated by `new` ([§§](#the-new-operator)) and that is initialized by `Point`'s constructor. Now consider the value assignment `$b = $a`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]] ^ | | | V V [VSlot $b *]-->[VStore Obj *]-----+ [VStore Int 1] [VStore Int 3]`$b`‘s VStore contains a handle that points to the same object as does `$a`‘s VStore’s handle. Note that the Point object itself was not copied, and note that `$a`’s and `$b`’s VSlots point to distinct VStores. Let's modify the value of the Point whose handle is stored in `$b` using `$b->move(4, 6)`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]] ^ | | | V V [VSlot $b *]-->[VStore Obj *]-----+ [VStore Int 4] [VStore Int 6] (1 was overwritten) (3 was overwritten)As we can see, changing `$b`'s Point changes `$a`'s as well. Now, let's make `$a` point to a different object using `$a = new Point(2, 1)`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]] | | [VSlot $b *]-->[VStore Obj *]-----+ V V | [VStore Int 2] [VStore Int 1] V [HStore Point [VSlot $x *] [VSlot $y *]] | | V V [VStore Int 4] [VStore Int 6]Before `$a` can take on the handle of the new `Point`, its handle to the old `Point` must be removed, which leaves the handles of `$a` and `$b` pointing to different Points. We can remove all these handles using `$a = NULL` and `$b = NULL`:
[VSlot $a *]-->[VStore Null] [HStore Point [VSlot $x *] [VSlot $y *] (dead)] | | [VSlot $b *]-->[VStore Null] [VStore Int 2 (dead)]<--+ V [VStore Int 1 (dead)] [HStore Point [VSlot $x *] [VSlot $y *] (dead)] | | [VStore Int 4 (dead)]<--+ V [VStore Int 6 (dead)]By assigning null to `$a`, we remove the only handle to `Point(2,1)`, which allows that object's destructor ([§§](#destructors)) to run. A similar thing happens with `$b`, as it too is the only handle to its Point. Although the examples above only show with only two instance properties, the same mechanics apply for value assignment of all object types, even though they can have an arbitrarily large number of instance properties of arbitrary type. Likewise, the same mechanics apply to value assignment of all resource types. ### # ByRef Assignment for Scalar Types with Local Variables Let's begin with the same value assignment ([§§](#simple-assignment)) as in the previous subclause, `$a = 123` and `$b = false`:
[VSlot $a *]-->[VStore Int 123] [VSlot $b *]-->[VStore Bool false]Now consider the byRef assignment ([§§](#byref-assignment)) `$b =& $a`, which has byRef semantics:
[VSlot $a *]-->[VStore Int 123] ^ | [VSlot $b *]-----+ [VStore Bool false (dead)]In this example, byRef assignment changes `$b`’s VSlot point to the same VStore that `$a`’s VSlot points to. The old VStore that `$b`’s VSlot used to point to is now unreachable. As stated in [§§](#general), it is not possible for a VSlot to point to another VSlot, so `$b`‘s VSlot cannot point to `$a`‘s VSlot. When multiple variables’ VSlots point to the same VStore, the variables are said to be *aliases* of each other or they are said to have an *alias relationship*. In the example above, after the byRef assignment executes the variables `$a` and `$b` will be aliases of each other. Now, let's observe what happens when we change the value of `$b` using `++$b`:
[VSlot $a *]-->[VStore Int 124 (123 was overwritten)] ^ | [VSlot $b *]-----+`$b`‘s value, which is stored in the VStore that `$b`’s VSlot points, is changed to 124. And as that VStore is also aliased by `$a`’s VSlot, the value of `$a` is also 124. Indeed, any variable’s VSlot that is aliased to that VStore will have the value 124. Now consider the value assignment `$a = 99`:
[VSlot $a *]-->[VStore Int 99 (124 was overwritten)] ^ | [VSlot $b *]-----+The alias relationship between `$a` and `$b` can be broken explicitly by using `unset` on variable `$a` or variable `$b`. For example, consider `unset($a)`:
[VSlot $a (dead)] [VStore Int 99] ^ | [VSlot $b *]-------------+Unsetting `$a` causes variable `$a` to be destroyed and its corresponding alias to the VStore to be removed, leaving `$c`’s VSlot as the only pointer remaining to the VStore. Other operations can also break an alias relationship between two or more variables. For example, `$a = 123` and `$b =& $a`, and `$c = 'hi'`:
[VSlot $a *]-->[VStore Int 123] ^ | [VSlot $b *]-----+ [VSlot $c *]-->[VStore Str 'hi']After the byRef assignment, `$a` and `$b` now have an alias relationship. Next, let's observe what happens for `$b = &$c`:
[VSlot $a *]-->[VStore Int 123] [VSlot $b *]-----+ | V [VSlot $c *]-->[VStore Str 'hi']As we can see, the byRef assignment above breaks the alias relationship between `$a` and `$b`, and now `$b` and `$c` are aliases of each other. When byRef assignment changes a VSlot to point to a different VStore, it breaks any existing alias relationship the left hand side variable had before the assignment operation. It is also possible to use byRef assignment to make three or more VSlots point to the same VStore. Consider the following example: ``` $b = &$a; $c = &$b; $a = 123; ```
[VSlot $a *]-->[VStore Int 123] ^ ^ | | [VSlot $b *]-----+ | | [VSlot $c *]---------+Like value assignment, byRef assignment provides a means for the programmer to created variables. If the local variables that appear on the left- or right-hand side of byRef assignment do not exist, the engine will bring new local variables into existence and create a VSlot and initial VStore for storing the local variable’s value. Note that literals, constants, and other expressions that don’t designate a modifiable lvalue cannot be used on the left- or right-hand side of byRef assignment. ### # Byref Assignment of Non-Scalar Types with Local Variables byRef assignment of non-scalar types works using the same mechanism as byRef assignment for scalar types. Nevertheless, it is worthwhile to describe a few examples to clarify the semantics of byRef assignment. Recall the example from [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable)) using the `Point` class: `$a = new Point(1, 3);`
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]] | | V V [VStore Int 1] [VStore Int 3]Now consider the byRef assignment ([§§](#byref-assignment)) `$b =& $a`, which has byRef semantics:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *][VSlot $y *]] ^ | | | V V [VSlot $b *]-----+ [VStore Int 1] [VStore Int 3]`$a` and `$b` now aliases of each other. Note that byRef assignment produces a different result than `$b = `$a where `$a` and `$b` would point to distinct VStores pointing to the same HStore. Let's modify the value of the `Point` aliased by `$a` using `$a->move(4, 6)`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *] VSlot $y *]] ^ | | | V V [VSlot $b *]-----+ [VStore Int 4] [VStore Int 6] (1 was overwritten) (3 was overwritten)Now, let's change `$a` itself using the value assignment `$a = new Point(2, 1)`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Point [VSlot $x *][VSlot $y *]] ^ | | | V V [VSlot $b *]-----+ [VStore Int 2] [VStore Int 1] [HStore Point [VSlot $x *] [VSlot $y *] (dead)] | | V V [VStore Int 4 (dead)] [VStore Int 6 (dead)]As we can see, `$b` continues to have an alias relationship with `$a`. Here's what's involved in that assignment: `$a` and `$b`'s VStore’s handle pointing to `Point(4,6)` is removed, `Point(2,1)` is created, and `$a` and `$b`’s VStore is overwritten to contain a handle pointing to that new `Point`. As there are now no VStores pointing to `Point(4,6)`, its destructor ([§§](#destructors)) can run. We can remove these aliases using `unset($a, $b)`:
[VSlot $a (dead)] [HStore Point [VSlot $x *] [VSlot $y *] (dead)] | | V V [VSlot $b (dead)] [VStore Int 2 (dead)] [VStore Int 1 (dead)]Once all the aliases to the VStores are gone, the VStores can be destroyed, in which case, there are no more pointers to the HStore, and its destructor ([§§]estructors](#Destructors)) can be run. ### # Value Assignment of Array Types to Local Variables The semantics of value assignment of array types is different from value assignment of other types. Recall the `Point` class from the examples in [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable), and consider the following value assignments ([§§](#simple-assignment)) and their abstract implementation: `$a = array(10, 'B' => new Point(1, 3));`
[VSlot $a *]-->[VStore Arr *]-->[HStore Array [VSlot 0 *] [VSlot 'B' *]] | | V V [VStore Int 10] [VStore Obj *] | [HStore Point [VSlot $x *] [VSlot $y *]]<--+ | | V V [VStore Int 1] [VStore Int 3]In the example above, `$a`‘s VStore is initialized to contain a handle to an HStore for an array containing two elements, where one element is an integer and the other is a handle to an HStore for an object. Now consider the following value assignment `$b = $a`. A conforming implementation must implement value assignment of arrays in one of the following ways: (1) eager copying, where the implementation makes a copy of `$a`’s array during value assignment and changes `$b`’s VSlot to point to the copy; or (2) deferred copying, where the implementation uses a deferred copy mechanism that meets certain requirements. This subclause describes eager copying, and the subclause that immediately follows ([§§](#deferred-array-copying)) describes deferred copying. To describe the semantics of eager copying, let’s begin by considering the value assignment `$b = $a`:
[VSlot $a *]-->[VStore Arr *]-->[HStore Array [VSlot 0 *] [VSlot 'B' *]] | | [VSlot $b *]-->[VStore Arr *] V V | [VStore Int 10] [VStore Obj *] V | [HStore Array [VSlot 0 *] [VSlot 'B' *]] | | | | +---------+ +---------+ | V V | [VStore Int 10] [VStore Obj *]-->[HStore Point [VSlot $x *] [VSlot $y *]]<---+ | | V V [VStore Int 1] [VStore Int 3]The value assignment `$b = $a` made a copy of `$a`’s array. Note how `$b`’s VSlot points to a different VStore than `$a`’s VSlot, and `$b`’s VStore points to a different HStore than `$b`’s VStore. Each source array element is copied using *member-copy assignment* `=*`, which is defined as follows: ``` $destination =* $source ``` - If `$source`’s VStore has a refcount equal to 1, the Engine copies the array element using value assignment (`destination = $source`). - If `$source`’s VStore has a refcount that is greater than 1, the Engine uses an implementation-defined algorithm to decide whether to copy the element using value assignment (`$destination = $source`) or byRef assignment (`$destination = &$source`). Note the member-copy assignment `=*` is **not** an operator or language construct in the PHP language, but instead it is used internally to describe behavior for the engine for array copying and other operations For the particular example above, member-copy assignment exhibits the same semantics as value assignment for all conforming implementations because all of the array elements’ VStores have a refcount equal to 1. The first element VSlots in `$a`’s array and `$b`’s array point to distinct VStores, each of which contain a distinct copy of the integer value 10. The second element VSlots in `$a`’s array and `$b`’s array point to distinct VStores, each of which contain a handle to the same object HStore. Let’s consider another example: ``` $x = 123; $a = array(array(&$x, 'hi')); $b = $a; ``` Eager copying can produce two possible outcomes depending on the implementation. Here is the first possible outcome:
[VSlot $a *]---->[VStore Arr *]---->[HStore Array [VSlot 0 *]] | [VSlot $x *]-------------------------+ [VStore Arr *]<---+ | | [VSlot $b *]-->[VStore Arr *] | V | | [HStore Array [VSlot 0 *][VSlot 1 *]] V | | | [HStore Array [VSlot 0 *]] | V | | +---------------->[VStore Int 123] | V ^ V [VStore Arr *] | [VStore Str 'hi'] | +--------------+ V | [HStore Array [VSlot 0 *] [VSlot 1 *]] | V [VStore Str 'hi']Here is the second possible outcome:
[VSlot $a *]---->[VStore Arr *]---->[HStore Array [VSlot 0 *]] | [VSlot $x *]-------------------------+ [VStore Arr *]<----+ | | [VSlot $b *]-->[VStore Arr *] | V | | [HStore Array [VSlot 0 *] [VSlot 1 *]] V | | | [HStore Array [VSlot 0 *]] | V | | +---------------->[VStore Int 123] | V V [VStore Arr *] [VStore Str 'hi'] | V [HStore Array [VSlot 0 *] [VSlot 1 *]] | | V V [VStore Int 123] [VStore Str 'hi']In both possible outcomes, value assignment with eager copying makes a copy of `$a`’s array, copying the array’s single element using member-copy assignment (which in this case will exhibit the same semantics of value assignment for all implementations), which in turn makes a copy of the inner array inside `$a`’s array, copying the inner array’s elements using member-copy assignment. The inner array’s first element VSlot points to a VStore that has a refcount that is greater than 1, so an implementation-defined algorithm is used to decide whether to use value assignment or byRef assignment. The first possible outcome shown above demonstrates what happens if the implementation chooses to do byRef assignment, and the second possible outcome shown above demonstrates what happens if the implementation chooses to do value assignment. The inner array’s second element VSlot points to a VStore that has a refcount equal to 1, so value assignment is used to copy the inner array’s second element for all conforming implementations that use eager copying. Although the examples in this subclause only use arrays with one element or two elements, the model works equally well for all arrays even though they can have an arbitrarily large number of elements. As to how an HStore accommodates all of them, is unspecified and unimportant to the abstract model. ### # Deferred Array Copying As mentioned in the previous subclause ([§§](#value-assignment-of-array-types-to-local-variables)), an implementation may choose to use a deferred copy mechanism instead of eagerly making a copy for value assignment of arrays. An implementation may use any deferred copy mechanism desired so long as it conforms to the abstract model’s description of deferred array copy mechanisms presented in this subclause. Because an array’s contents can be arbitrarily large, eagerly copying an array’s entire contents for value assignment can be expensive. In practice an application written in PHP may rely on value assignment of arrays being relatively inexpensive for the common case (in order to deliver acceptable performance), and as such it is common for an implementation to use a deferred array copy mechanism in order to reduce the cost of value assignment for arrays. Unlike conforming deferred string copy mechanisms discussed in [§§](#value-assignment-of-scalar-types-to-a-local-variable) that must produce the same observable behavior as eager string copying, deferred array copy mechanisms are allowed in some cases to exhibit observably different behavior than eager array copying. Thus, for completeness this subclause describes how deferred array copies can be modeled in the abstract memory model and how conforming deferred array copy mechanisms must behave. Conforming deferred array copy mechanisms work by not making an array copy during value assignment, by allowing the destination VStore to share an array HStore with the source VStore, and by making a copy of the array HStore at a later time if or when it is necessary. The abstract model represents a deferred array copy relationship by marking the destination VStore with a special “Arr-D” type tag and by sharing the same array HStore between the source and destination VStores. Note that the source VStore’s type tag remains unchanged. For the purposes of this abstract model, the “Arr-D” type tag is considered identical to the “Arr” type in all respects except when specified otherwise. To illustrate this, let’s see how the previous example would be represented under the abstract model assuming the implementation defers the copying the array: ``` $x = 123; $a = array(array(&$x, ‘hi’)); $b = $a; ```
[VSlot $a *]--->[VStore Arr *]--->[HStore Array [VSlot 0 *]] ^ | | [VStore Arr *]<--+ [VSlot $b *]--->[VStore Arr-D *]----+ | V [HStore Array [VSlot 0 *] [VSlot 1 *]] | | V | [VSlot $x *]------------------------------------------>[VStore Int 123] | V [VStore Str 'hi']As we can see, both `$a`’s VStore (the source VStore) and `$b`’s VStore (the destination VStore) point to the same array HStore. Note the asymmetric nature of how deferred array copies are represented in the abstract model. In the above example the source VStore’s type tag remains unchanged after value assignment, whereas the destination VStore’s type tag was changed to “Arr-D”. When the engine is about to perform an array-mutating operation on a VStore tagged “Arr” that participates in a deferred array copy relationship or on a VStore tagged “Arr-D”, the engine must first take certain actions that involve making a copy of the array (described in the next paragraph) before performing the array-mutating operation. An array-mutating operation is any operation can add or remove array elements, overwrite existing array elements, change the state of the array’s internal cursor, or cause the refcount of one or more of the array’s element VStores or subelement VStores to increase from 1 to a value greater than 1. This requirement to take certain actions before performing an array-mutation operation on a VStore participating in a deferred array copy relationship is commonly referred to as the copy-on-write requirement. When an array-mutating operation is about to be performed on a given VStore X with an “Arr” type tag that participates in a deferred array copy relationship, the engine must find all of the VStores tagged “Arr-D” that point to the same array HStore that VStore X points to, make a copy of the array (using member-copy assignment to copy the array’s elements as described in [§§](#value-assignment-of-array-types-to-local-variables)), and update all of these VStores tagged “Arr-D” to point to the newly created copy (note that VStore X remains unchanged). When an array-mutation operation is about to be performed on a given VStore X with an “Arr-D” type tag, the engine must make a copy of the array (as described in [§§](#value-assignment-of-array-types-to-local-variables)), update VStore X to point to the newly created copy, and change VStore X’s type tag to “Arr”. These specific actions that the engine must perform on VStore at certain times to satisfy the copy-on-write requirement are collectively referred to as “array-separation” or “array-separating the VStore”. An array-mutation operation is said to “trigger” an array-separation. Note that for any VStore with an “Arr” type tag that participates in a deferred array copy relationship, or for any VStore with an “Arr-D” type tag, a conforming implementation may choose to array-separate the VStore at any time for any reason as long as the copy-on-write requirement is upheld. Continuing with the previous example, consider the array-mutating operation `$b[1]++`. Depending on the implementation, this can produce one of three possible outcomes. Here is the one of the possible outcomes:
[VSlot $a *]---->[VStore Arr *]---->[HStore Array [VSlot 0 *]] | [VSlot $b *]-->[VStore Arr *] [VStore Arr *]<---+ | | +----------------------+ +--------+ V V [HStore Array [VSlot 0 *] [VSlot 1 *]] [HStore Array [VSlot 0 *] [VSlot 1 *]] | | ^ | | | V | V | | [VStore Int 1] | [VStore Int 123] | V | ^ V [VStore Arr-D *]-----+ | [VStore Str 'hi'] | [VSlot $x *]----------------------------------------------+As we can see in the outcome shown above, `$b`’s VStore was array-separated and now `$a`’s VStore and `$b`’s VStore point to distinct array HStores. Performing array-separation on `$b`’s VStore was necessary to satisfy the copy-on-write requirement. `$a`’s array remains unchanged and that `$x` and `$a[0][0]` still have an alias relationship with each other. For this particular example, conforming implementations are required to preserve `$a`’s array’s contents and to preserve the alias relationship between `$x` and `$a[0][0]`. Finally, note that `$a[0]` and `$b[0]` have a deferred copy relationship with each other in the outcome shown above. For this particular example, a conforming implementation is not required to array-separate `$b[0]`’s VStore, and the outcome shown above demonstrates what happens when `$b[0]`’s VStore is not array-separated. However, an implementation can choose to array-separate `$b[0]`’s VStore at any time if desired. The other two possible outcomes shown below demonstrate what can possibly happen if the implementation choose to array-separate `$b[0]`’s VStore as well. Here is the second possible outcome:
[VSlot $a *]---->[VStore Arr *]---->[HStore Array [VSlot 0 *]] | [VSlot $b *]-->[VStore Arr *] [VStore Arr *]<---+ | | V V [HStore Array [VSlot 0 *] [VSlot 1 *]] [HStore Array [VSlot 0 *] [VSlot 1 *]] | | | | +-----------------+ V | | | [VStore Int 1] +---+ | V | V [VStore Arr-D *]-->[HStore Array [VSlot 0 *] [VSlot 1 *]] | [VStore Str 'hi'] | | | +-------+ | | | V | | [VStore Str ‘hi’] | V | [VSlot $x *]--------------------->[VStore Int 123]<--------+Here is the third possible outcome:
[VSlot $a *]---->[VStore Arr *-]---->[HStore Array [VSlot 0 *]] | [VSlot $b *]-->[VStore Arr *] [VStore Arr *]<---+ | | V V [HStore Array [VSlot 0 *] [VSlot 1 *]] [HStore Array [VSlot 0 *] [VSlot 1 *]] | | | | +-----------------+ V | | | [VStore Int 1] +---+ | V | V [VStore Arr-D *]-->[HStore Array [VSlot 0 *] [VSlot 1 *]] | [VStore Str 'hi'] | | | [VStore Int 123]<-------+ | | V | [VStore Str 'hi'] | | [VSlot $x *]--------------------->[VStore Int 123]<--------+The second and third possible outcomes show what can possibly happen if the implementation chooses to array-separate `$b[0]`’s VStore. In the second outcome, `$b[0][0]` has an alias relationship with `$x` and `$a[0][0]`. In the third outcome, `$b[0][0]` does not have an alias relationship, though `$x` and `$a[0][0]` still have an alias relationship with each other. The differences between the second and third outcome are reflect that different possibilities when the engine uses member-copy assignment to copy `$a[0]`’s arrays’s elements into `$b[0]`’s array. Finally, let’s briefly consider one more example: ``` $x = 0; $a = array(&$x); $b = $a; $x = 2; unset($x); $b[1]++; $b[0]++; echo $a[0], ' ', $b[0]; ``` For the example above, a conforming implementation could output “2 1”, “2 3”, or “3 3” depending on how it implements value assignment for arrays. For portability, it is generally recommended that programs written in PHP should avoid performing value assignment with a right-hand side that is an array with one or more elements or sub-elements that have an alias relationship. ***Implementation Notes:*** For generality and for simplicity, the abstract model represents deferred array copy mechanisms in a manner that is more open-ended and superficially different than the php.net implementation’s model, which uses a symmetric deferred copy mechanism where a single zval contains the sole pointer to a given Hashtable and deferred array copies are represented as multiple slots pointing to the same single zval that holds the array. Despite this superficial difference, php.net’s implementation produces behavior that is compatible with the abstract model’s definition of deferred array copy mechanisms. ### # General Value Assignment The subclauses above thus far have described the mechanics of value assignment to a local variable. This subclause describes how value assignment works when general modifiable lvalue expressions are used on the left hand side. **[TODO: Add description and examples here involving array elements and object instance properties. Describe how new array elements and object instance properties can be created via value assignment.]** ### # General ByRef Assignment The subclauses above thus far have described the mechanics of byref assignment with local variables. This subclause describes how byref assignment works when general modifiable lvalue expressions are used on the left hand side and/or the right hand side. **[TODO: Add description and examples here involving array elements and object instance properties. Describe how new array elements and object instance properties can be created via byref assignment.]** ## # Argument Passing Argument passing is defined in terms of simple assignment ([§§](#value-assignment-of-scalar-types-to-a-local-variable), [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable), [§§](#value-assignment-of-array-types-to-local-variables), and [§§](#simple-assignment)) or byRef assignment ([§§]), [§§](#byref-assignment-of-non-scalar-types-with-local-variables), and [§§](#byref-assignment)), depending on how the parameter is declared. That is, passing an argument to a function having a corresponding parameter is like assigning that argument to that parameter. The function-call situations involving missing arguments or undefined-variable arguments are discussed in ([§§](#function-call-operator)). ## # Value Returning Returning a value from a function is defined in terms of simple assignment ([§§](#value-assignment-of-scalar-types-to-a-local-variable), [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable), [§§](#value-assignment-of-array-types-to-local-variables), and [§§](#simple-assignment)) or byRef assignment ([§§](#byref-assignment-for-scalar-types-with-local-variables), [§§](#byref-assignment-of-non-scalar-types-with-local-variables), and [§§](#byref-assignment)) depending on how the function is declared. That is, returning a value from a function to its caller is like assigning that value to the user of the caller's return value. The function-return situations involving a missing return value are discussed in ([§§](#function-call-operator)). ## # Cloning objects When an instance is allocated, operator `new` ([§§](#the-new-operator)) returns a handle that points to that object. As described in [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable)), value assignment of a handle to an object does not copy the object HStore itself. Instead, it creates a copy of the handle. How then to make a copy of the object itself? Our only access to it is via the handle. The PHP language allows us to do this via operator `clone` ([§§](#the-clone-operator)). To demonstrate how the `clone` operator works, consider the case in which an instance of class `Widget` contains two instance properties: `$p1` has the integer value 10, and `$p2` is a handle to an array of elements of some type(s) or to an instance of some other type.
[VSlot $a *]-->[VStore Obj *]-->[HStore Widget [VSlot $p1 *][VSlot $p2 *]]
| |
V V
[VStore Int 10] [VStore Obj *]
|
V
[HStore ...]
Let us consider the result of `$b = clone $a`:
[VSlot $a *]-->[VStore Obj *]-->[HStore Widget [VSlot $p1 *][VSlot $p2 *]] | | [VSlot $b *]-->[VStore Obj *] V V | [VStore Int 10] [VStore Obj *] +-----------------------+ | V V [HStore Widget [VSlot $p1 *] [VSlot $p2 *]] +--->[HStore ...] | | | V V | [VStore Int 10] [VStore Obj *]-------------+The clone operator will create another object HStore of the same class as the original, copy `$a`’s object’s instance properties using member-copy assignment `=*` ([§§](#value-assignment-of-array-types-to-local-variables)). For the example shown above, the handle to the newly created HStore stored into `$b` using value assignment. Note that the clone operator will not recursively clone objects held in `$a`’s instance properties; hence the object copying performed by the clone operator is often referred to as a *shallow copy*. If a *deep copy* of an object is desired, the programmer must achieve this manually by using the method `__clone` ([§§](#method-__clone)) or by other means. # # Scope The same name can designate different things at different places in a program. For each different thing that a name designates, that name is visible only within a part of the program called that name's *scope*. The following distinct scopes exist: - Script, which means from the point of declaration/first initialization through to the end of that script, including any included and required files ([§§](#general-16)). - Function, which means from the point of declaration/first initialization through to the end of that function ([§§](#function-definitions)). - Class, which means the body of that class and any classes derived from it ([§§](#class-declarations)). - Interface, which means the body of that interface, any interfaces derived from it, and any classes that implement it ([§§](#interface-declarations)). - Namespace, which means from the point of declaration/first initialization through to the end of that namespace ([§§](#general-28)). A variable declared or first initialized inside a function, has function scope; otherwise, the variable has script scope. Superglobals ([§§](#general-5)) are always in scope; they never need explicit declaration. Each function has its own function scope. An anonymous function ([§§](#anonymous-functions)) has its own scope separate from that of any function inside which that anonymous function is defined. The scope of a parameter is the body of the function in which the parameter is declared. For the purposes of scope, a catch-block ([§§](#the-try-statement)) is treated like a function body, in which case, the *variable-name* in *parameter-declaration-list* is treated like a parameter. The scope of a *named-label* ([§§](#labeled-statements)) is the body of the function in which the label is defined. The scope of a class member m ([§§](#class-members)) declared in, or inherited by, a class type C is the body of C. The scope of an interface member m ([§§](#class-members)) declared in, or inherited by, an interface type I is the body of I. When a trait ([§§](#general-26)) is used by a class or an interface, the trait's members ([§§](#trait-members)) take on the scope of a member of that class or interface. # # Storage Duration The lifetime of a variable is the time during program execution that storage for that variable is guaranteed to exist. This lifetime is referred to as the variable's *storage duration*, of which there are three kinds: automatic, static, and allocated. A variable having *automatic storage duration* comes into being and is initialized at its declaration or on its first use, if it has no declaration. Its lifetime is delimited by an enclosing scope ([§§](#scope)). The automatic variable's lifetime ends at the end of that scope. Automatic variables lend themselves to being stored on a stack where they can help support argument passing and recursion. Local variables ([§§](#local-variables)), which include function parameters ([§§](#function-definitions)), have automatic storage duration. A variable having *static storage duration* comes into being and is initialized before its first use, and lives until program shutdown. The following kinds of variables have static storage duration: constants ([§§](#constants-1)), function statics ([§§](#function-statics)), global variables ([§§](#global-variables)), static properties ([§§](#static-properties)), and class and interface constants ([§§](#class-and-interface-constants)). A variable having *allocated storage duration* comes into being based on program logic by use of the new operator ([§§](#the-new-operator)). Ordinarily, once such storage is no longer needed, it is reclaimed automatically by the Engine via its garbage-collection process ([§§](#)) and the use of destructors ([§§](#destructors)). The following kinds of variables have allocated storage duration: array elements ([§§](#array-elements)) and instance properties ([§§](#instance-properties)). Although all three storage durations have default ends-of-life, their lives can be shortened by calling the intrinsic unset ([§§](#unset)), which destroys any given set of variables. The following example demonstrates the three storage durations: ``` class Point { ... } $av1 = new Point(0, 1); // auto variable $av1 created and initialized static $sv1 = ...; // static variable $sv1 created and initialized function doit($p1) { $av2 = ...; // auto variable $av2 created and initialized static $sv2 = ...; // static variable $sv2 created and initialized if ($p1) { $av3 = ...; // auto variable $av3 created and initialized static $sv3 = ...; // static variable $sv3 created and initialized ... } global $av1; $av1 = new Point(2, 3); // Point(0,1) is eligible for destruction ... } // $av2 and $av3 are eligible for destruction doit(TRUE); // At end of script, $av1, $sv1, $sv2, and $sv3 are eligible for destruction ``` The comments indicate the beginning and end of lifetimes for each variable. In the case of the initial allocated Point variable whose handle is stored in `$av1`, its life ends when `$av1` is made to point to a different Point. If function `doit` is called multiple times, each time it is called, its automatic variables are created and initialized, whereas its static variables retain their values from previous calls. Consider the following recursive function: ``` function factorial($i) { if ($i > 1) return $i * factorial($i - 1); else if ($i == 1) return $i; else return 0; } ``` When `factorial` is first called, the local variable parameter `$i` is created and initialized with the value of the argument in the call. Then, if this function calls itself, the same process is repeated each call. Specifically, each time `factorial` calls itself, a new local variable parameter `$i` is created and initialized with the value of the argument in the call. The lifetime of any VStore (§[[4.4.1](#general)](#general)) or HStore (§[[4.4.1](#general)](#general)) can be extended by the Engine as long as needed. Conceptually, the lifetime of a VStore ends when it is no longer pointed to by any VSlots ([§§](#general)). Conceptually, the lifetime of an HStore ends when no VStores have a handle to it. # Types # # General The meaning of a value is determined by its *type*. PHP's types are categorized as *scalar types* and *composite types*. The scalar types are Boolean ([§§](#the-boolean-type)), integer ([§§](#the-integer-type)), floating-point ([§§](#the-floating-point-type)), string ([§§](#the-string-type)), and null ([§§](#the-null-type)). The composite types are array ([§§](#array-types)), object ([§§](#object-types)), and resource ([§§](#resource-types)). The scalar types are *value types*. That is, a variable of scalar type behaves as though it contains its own value. On the other hand, the composite types are *handle types*. A variable of composite type contains information—in a *handle*—that leads to the value. The differences between value and handle types become apparent when it comes to understanding the semantics of assignment, and passing arguments to, and returning values from, functions ([§§](#the-memory-model)). That said, array types really are a hybrid; on the one hand, an array may contain an arbitrary number of elements separate from the array variable itself, yet on the other hand, certain array operations do have value semantics. Variables are not declared to have a particular type. Instead, a variable's type is determined at runtime by the context in which it is used. Useful library functions for interrogating and using type information include `gettype` (§xx), `is_type` (§xx), `settype` (§xx), and `var_dump` (§xx). # # Scalar Types ## # General The integer and floating-point types are collectively known as *arithmetic types*. The library function `is_numeric` (§xx) indicates if a given value is a number or a numeric string ([§§](#the-string-type)). The library function `is_scalar` (§xx) indicates if a given value has a scalar type. However, that function does not consider `NULL` to be scalar. To test for `NULL`, use `is_null` (§xx). ## # The Boolean Type The Boolean type is `bool`, for which the name boolean is a synonym. This type is capable of storing two distinct values, which correspond to the Boolean values `TRUE` and `FALSE` ([§§](#core-predefined-constants)), respectively. The representation of this type and its values is unspecified. The library function `is_bool` (§xx) indicates if a given value has type bool. ## # The Integer Type There is one integer type, `int`, for which the name integer is a synonym. This type is binary, signed, and uses twos-complement representation for negative values. The range of values that can be stored is implementation-defined; however, the range [-2147483648, 2147483647], must be supported. Certain operations on integer values produce a mathematical result that cannot be represented as an integer. Examples include the following: - Incrementing the largest value or decrementing the smallest value - Applying the unary minus to the smallest value - Multiplying, adding, or subtracting two values In such cases, the resulting type and value is implementation-defined, but must be one of the following: - The computation is done as though the types of the values were `float` with the result having that type - The result type is int and the value reflects wrap-around (for example adding 1 to the largest value results in the smallest value) - The computation is done as though the type had some unspecified, arithmetic-like object type with the result being mathematically correct The constants `PHP_INT_SIZE` (§[[6.3](#core-predefined-constants)](#core-predefined-constants)) and `PHP_INT_MAX` (§[[6.3](#core-predefined-constants)](#core-predefined-constants)) define certain characteristics about type `int`. The library function `is_int` (§xx) indicates if a given value has type int. ## # The Floating-Point Type There is one floating-point type, `float`, for which the names `double` and `real` are synonyms. The `float` type must support at least the range and precision of IEEE 754 64-bit double-precision representation. The library function `is_float` (§xx) indicates if a given value has type `float`. The library function `is_finite` (§xx) indicates if a given floating-point value is finite. The library function `is_infinite` (§xx) indicates if a given floating-point value is infinite. The library function `is_nan` (§xx) indicates if a given floating-point value is a `NaN`. ## # The String Type A string is a set of contiguous bytes that represents a sequence of zero or more characters. Conceptually, a string can be considered as an array ([§§](#array-types)) of bytes—the *elements*—whose keys are the `int` values starting at zero. The type of each element is `string`. However, a string is *not* considered a collection, so it cannot be iterated over. A string whose length is zero is an *empty string*. As to how the bytes in a string translate into characters is unspecified. Although a user of a string might choose to ascribe special semantics to bytes having the value `U+0000`, from PHP's perspective, such *null bytes* are simply just bytes! PHP does not assume strings contain any specific data or assign special values to any bytes or sequences. However, many library functions assume the strings they receive as arguments are UTF-8 encoded, often without explicitly mentioning that fact. A *numeric string* is a string whose content exactly matches the pattern defined using integer format by the production *integer-literal* ([§§](#integer-literals)) or using floating-point format by the production *floating-literal* ([§§](#floating-point-literals)), where leading whitespace is permitted. A *leading-numeric string* is a string whose initial characters follow the requirements of a numeric string, and whose trailing characters are non-numeric. A *non-numeric string* is a string that is not a numeric string. Only one mutation operation may be performed on a string, offset assignment, which involves the simple assignment operator = ([§§](#simple-assignment)). The library function `is_string` (§xx) indicates if a given value has type string. ## # The Null Type The null type has only one possible value, `NULL` ([§§](#core-predefined-constants)). The representation of this type and its value is unspecified. The library function `is_null` (§xx) indicates if a given value is `NULL`. # # Composite Types ## # Array Types An array is a data structure that contains a collection of zero or more elements whose values are accessed through keys that are of type `int` or `string`. Arrays are described in [§§](#arrays). The library function `is_array` (§xx) indicates if a given value is an array. ## # Object Types An *object* is an instance of a class ([§§](#classes)). Each distinct *class-declaration* ([§§](#class-declarations)) defines a new class type, and each class type is an object type. The representation of object types is unspecified. The library function `is_object` (§xx) indicates if a given value is an object, and the library function [`get_class`](http://us2.php.net/manual/en/function.get-class.php) (§xx) indicates the name of an object's class. ## # Resource Types A [*resource*](http://www.php.net/manual/en/language.types.resource.php) is a descriptor to some sort of external entity. (Examples include files, databases, and sockets.) A resource is an abstract entity whose representation is unspecified. Resources are only created or consumed by the implementation; they are never created or consumed by PHP code. Each distinct resource has a unique ID of some unspecified form. When scripts execute in a mode having a command-line interface, the following predefined resource constants that correspond to file streams are automatically opened at program start-up: - STDIN, which maps to standard input (php://stdin) - STDOUT, which maps to standard output (php://stdout) - STDERR, which maps to standard error (php://stderr) The library function `is_resource` (§xx) indicates if a given value is a resource, and the library function [`get_resource_type`](http://us2.php.net/manual/en/function.get-resource-type.php) (§xx) indicates the type of a resource. # Constants # # General A *constant* is a name ([§§](#names)) for a value that once given its initial value, cannot be changed. A constant can be defined in one of two ways: as a *c-constant* using a *const-declaration* ([§§](#constants-2)), or as a *d-constant* by calling the library function `define` (§xx). However, the two approaches differ slightly. Specifically: - The name of a c-constant must comply with the lexical grammar for a name while that for a d-constant can contain any source character. - The name of a c-constant is case-insensitive while that for a d-constant can be case-sensitive or case-insensitive based on the value of the third argument passed to `define`. - If `define` is able to define the given name, it returns `TRUE`; otherwise, it returns `FALSE`. The library function `defined` (§xx) reports if a given name (specified as a string) is defined as a constant. The library function `constant` (§xx) returns the value of a given constant whose name is specified as a string. **Examples** ``` const MAX_HEIGHT = 10.5; // define two (case-insensitive) c-constants const UPPER_LIMIT = MAX_HEIGHT; define('COEFFICIENT_1', 2.345, TRUE); // define a case-insensitive d-constant define('FAILURE', TRUE, FALSE); // define a case-sensitive d-constant ``` # # Context-Dependent Constants The following constants—sometimes referred to as *magic constants*—are automatically available to all scripts; their values are not fixed: Constant Name | Description ----------------- | --------- `__CLASS__` | `string`; The name of the current class. From within a trait method, the name of the class in which that trait is used. If the current namespace is other than the default, the namespace name and "\\" are prepended, in that order. If used outside all classes, the result is the empty string. `__DIR__` | `string`; The directory name of the script. A directory separator is only appended for the root directory. `__FILE__` | `string`; The full name of the script. `__FUNCTION__` | `string`; Inside a function, the name of the current function exactly as it was declared, with the following prepended: If a named namespace exists, that namespace name followed by "\". If used outside all functions, the result is the empty string. For a method, no parent-class prefix is present. (See `__METHOD__` and [§§](#anonymous-functions).) `__LINE__` | `int`; the number of the current source line `__METHOD__` | `string`; Inside a method, the name of the current method exactly as it was declared, with the following prepended, in order: If a named namespace exists, that namespace name followed by "\"; the parent class name or trait name followed by `::`. If used outside all methods, the result is the same as for `__FUNCTION__`. `__NAMESPACE__` | `string`; The name of the current namespace exactly as it was declared. For the default namespace, the result is the empty string. `__TRAIT__` | `string`; The name of the current trait. From within a trait method, the name of the current trait. If used outside all traits, the result is the empty string. Constants beginning with __ are reserved for future use by the Engine. # # Core Predefined Constants The following constants are automatically available to all scripts: Constant Name | Description ------------- | ----------- `__COMPILER_HALT_OFFSET__` | `int`; When the library function `__HALT_COMPILER__` (§xx) is called, this constant contains the location in the source file immediately following the `__HALT_COMPILER__()`; token. `DEFAULT_INCLUDE_PATH` | `string`; the `fopen` library function (§xx) include path is used if it is not overridden by the `php.ini` setting `include_path`. `E_ALL` | `int`; All errors and warnings, as supported. `E_COMPILE_ERROR` | `int`; Fatal compile-time errors. This is like an `E_ERROR`, except that `E_COMPILE_ERROR` is generated by the scripting engine. `E_COMPILE_WARNING` | `int`; Compile-time warnings (non-fatal errors). This is like an `E_WARNING`, except that `E_COMPILE_WARNING` is generated by the scripting engine. `E_CORE_ERROR` | `int`; Fatal errors that occur during PHP's initial start-up. This is like an `E_ERROR`, except that `E_CORE_ERROR` is generated by the core of PHP. `E_CORE_WARNING` | `int`; Warnings (non-fatal errors) that occur during PHP's initial start-up. This is like an `E_WARNING`, except that `E_CORE_WARNING` is generated by the core of PHP. `E_DEPRECATED` | `int`; Run-time notices. Enable this to receive warnings about code that will not work in future versions. `E_ERROR` | `int`; Fatal run-time errors. These indicate errors that cannot be recovered from, such as a memory allocation problem. Execution of the script is halted. `E_NOTICE` | `int`; Run-time notices. Indicate that the script encountered something that could indicate an error, but could also happen in the normal course of running a script. `E_PARSE` | `int`; Compile-time parse errors. `E_RECOVERABLE_ERROR` | `int`; Catchable fatal error. It indicates that a probably dangerous error occurred, but did not leave the Engine in an unstable state. If the error is not caught by a user defined handler (see the library function `set_error_handler` (§xx)), the application aborts as it was an `E_ERROR`. `E_STRICT` | `int`; Have PHP suggest changes to the source code to ensure the best interoperability. `E_USER_DEPRECATED` | `int`; User-generated error message. This is like an `E_DEPRECATED`, except that `E_USER_DEPRECATED` is generated in PHP code by using the library function `trigger_error` (§xx). `E_USER_ERROR` | `int`; User-generated error message. This is like an `E_ERROR`, except that `E_USER_ERROR` is generated in PHP code by using the library function `trigger_error` (§xx). `E_USER_NOTICE` | `int`; User-generated warning message. This is like an `E_NOTICE`, except that `E_USER_NOTICE` is generated in PHP code by using the library function `trigger_error` (§xx). `E_USER_WARNING` | `int`; User-generated warning message. This is like an `E_WARNING`, except that `E_USER_WARNING` is generated in PHP code by using the library function `trigger_error` (§xx). `E_WARNING` | `int`; Run-time warnings (non-fatal errors). Execution of the script is not halted. `E_USER_DEPRECATED` | `int`; User-generated warning message. This is like an `E_DEPRECATED`, except that `E_USER_DEPRECATED` is generated in PHP code by using the library function `trigger_error` (§xx). `FALSE` | `bool`; the case-insensitive Boolean value `FALSE`. `INF` | `float`; Infinity `M_1_PI` | `float`; 1/pi `M_2_PI` | `float`; 2/pi `M_2_SQRTPI` | `float`; 2/sqrt(pi) `M_E` | `float`; e `M_EULER` | `float`; Euler constant `M_LN10` | `float`; log_e 10 `M_LN2` | `float`; log_e 2 `M_LNPI` | `float`; log_e(pi) `M_LOG10E` | `float`; log_10 e `M_LOG2E` | `float`; log_2 e `M_PI` | `float`; Pi `M_PI_2` | `floa`t; pi/2 `M_PI_4` | `float`; pi/4 `M_SQRT1_2` | `float`; 1/sqrt(2) `M_SQRT2` | `float`; sqrt(2) `M_SQRT3` | `float`; sqrt(3) `M_SQRTPI` | `float`; sqrt(pi) `NAN` | `float`; Not-a-Number `NULL` | `null`; the case-insensitive value `NULL`. `PHP_BINARY` | `string`; the PHP binary path during script execution. `PHP_BINDIR` | `string`; the installation location of the binaries. `PHP_CONFIG_FILE_PATH` | `string`; location from which php.ini values were parsed `PHP_CONFIG_FILE_SCAN_DIR` | `string`; The directory containing multiple INI files, all of which were parsed on start-up. `PHP_DEBUG` | `int`; Indicates whether the engine was built with debugging enabled. `PHP_EOL` | `string`; the end-of-line terminator for this platform. `PHP_EXTENSION_DIR` | `string`; The directory to be searched by the library function dl (§xx) when looking for runtime extensions. `PHP_EXTRA_VERSION` | `string`; the current PHP extra version. `PHP_INT_MAX` | `int`; the largest representable value for an integer. `PHP_INT_SIZE` | `int`; the number of bytes used to represent an integer. `PHP_MAJOR_VERSION` | `int`; the current PHP major version `PHP_MANDIR` | `string`; the installation location of the manual pages. `PHP_MAXPATHLEN` | `int`; the maximum length of a fully qualified filename supported by this build. `PHP_MINOR_VERSION` | `int`; the current PHP minor version `PHP_OS` | `string`; the current operating system. `PHP_PREFIX` | `string`; the value to which "--prefix" was set when configured. `PHP_RELEASE_VERSION` | `int`; the current PHP release version `PHP_ROUND_HALF_DOWN` | `int`; Round halves down `PHP_ROUND_HALF_EVEN` | `int`; Round halves to even numbers `PHP_ROUND_HALF_ODD` | `int`; Round halves to odd numbers `PHP_ROUND_HALF_UP` | `int`; Round halves up `PHP_SAPI | `string`; the Server API for this build. `PHP_SHLIB_SUFFIX` | `string`; build-platform's shared library suffix. `PHP_SYSCONFDIR` | `string`; the PHP system configuration directory.xx `PHP_VERSION` | `string`; the current PHP version in the form "major.minor.release[extra]". `PHP_VERSION_ID` | `int`; the current PHP version `PHP_ZTS` | `int`; Indicates whether the compiler was built with thread safety enabled. `TRUE` | `bool`; the case-insensitive Boolean value `TRUE`. The members of the `E_\*` family have values that are powers of 2, so they can be combined meaningfully using bitwise operators. # # User-Defined Constants A constant may be defined inside or outside of functions ([§§](#constants-2)), inside a class ([§§](#constants-2)), or inside an interface ([§§](#constants-3)). # Variables # # General A *variable* is a named area of data storage that has a type and a value, both of which can change. A variable is represented by a VSlot ([§§](#general)). A variable is created by assigning a value to it ([§§](#assignment), [§§](#simple-assignment), [§§](#byref-assignment), [§§](#the-new-operator), [§§](#array-creation-operator)). A variable is destroyed by *unsetting* it, either by an explicit call to the intrinsic unset ([§§](#unset)), or by the Engine. The intrinsic `isset` ([§§](#isset)) tests if a given variable exists and is not set to `NULL`. A variable that somehow becomes defined, but is not initialized starts out with the value `NULL`. Variables have names as defined in [§§](#names). Distinct variables may have the same name provided they are in different scopes ([§§](#scope)). A constant ([§§](#general-4)) is a variable that, once initialized, its value cannot be changed. Based on the context in which it is declared, a variable has a scope ([§§](#scope)) and a storage duration ([§§](#storage-duration)). A *superglobal* variable is one that is accessible in all scopes without the need for a *global-declaration* ([§§](#global-variables)). The following kinds of variable may exist in a script: - Constant ([§§](#constants-1)) - Local variable ([§§](#local-variables)) - Array element ([§§](#array-elements)) - Function static ([§§](#function-statics)) - Global variable ([§§](#global-variables)) - Instance property ([§§](#instance-properties)) - Static property ([§§](#static-properties)) - Class and interface constant ([§§](#class-and-interface-constants)) # # Kinds of Variables ## # Constants **Syntax:** See [§§](#general-4). **Constraints:** Outside of a class or interface, a c-constant can be defined only at the top level of a script. **Semantics:** See [§§](#general-4) and [§§](#constants-2). A constant defined outside of a class or interface is a superglobal ([§§](#general-5)). A constant defined inside a function has function scope ([§§](#scope)). A constant defined at the top level has script scope. A constant has static storage duration ([§§](#storage-duration)) and is a non-modifiable lvalue. **Examples** ``` const MAX_HEIGHT = 10.5; // define two c-constants const UPPER_LIMIT = MAX_HEIGHT; define('COEFFICIENT_1', 2.345); // define two d-constants define('FAILURE', TRUE); ``` ## # Local Variables **Syntax:** See Semantics below. Semantics: Except for a parameter, a local variable is never defined explicitly; instead, it is created when it is first assigned a value. A local variable can be assigned to as a parameter in the parameter list of a function definition ([§§](#function-definitions)) or inside any compound statement ([§§](#compound-statements)). It has function scope ([§§](#scope)) and automatic storage duration ([§§](#storage-duration)). A local variable is a modifiable lvalue. **Examples** ``` function doit($p1) // assigned the value TRUE when called { $count = 10; ... if ($p1) { $message = "Can't open master file."; ... } ... } doit(TRUE); // ----------------------------------------- function f() { $lv = 1; echo "\$lv = $lv\n"; ++$lv; } for ($i = 1; $i <= 3; ++$i) f(); ``` Unlike the function static equivalent in [§§](#function-statics), function `f` outputs "`$lv = 1`" each time. See the recursive function example in [§§](#storage-duration). ## # Array Elements **Syntax:** Arrays ([§§](#arrays)) are created via the array-creation operator ([§§](#array-creation-operator)) or the intrinsic `array` ([§§](#array)). At the same time, one or more elements may be created for that array. New elements are inserted into an existing array via the simple-assignment operator ([§§](#simple-assignment)) in conjunction with the subscript operator `[]` ([§§](#subscript-operator)). Elements can be removed by calling the `unset` intrinsic ([§§](#unset)). **Semantics:** The scope ([§§](#scope)) of an array element is the same as the scope of that array's name. An array element has allocated storage duration ([§§](#storage-duration)). **Examples** ``` $colors = ["red", "white", "blue"]; // create array with 3 elements $colors[] = "green"; // insert a new element ``` ## # Function Statics **Syntax:**
function-static-declaration:
static name function-static-initializeropt ;
function-static-initializer:
= const-expression
*name* is defined in ([§§](#names)), and *const-expression* is defined in
([§§](#constant-expressions)).
**Constraints:**
A function static must be defined inside a function.
**Semantics:**
A function static may be defined inside any compound statement ([§§](#compound-statements)).
It is a modifiable lvalue.
A function static has function scope ([§§](#scope)) and static storage duration
([§§](#storage-duration)).
The value of a function static is retained across calls to its parent
function. Each time the function containing a function static
declaration is called, that execution is dealing with an alias ([§§](#general))
to that static variable. If that alias is passed to the `unset` intrinsic
([§§](#unset)), only that alias is destroyed. The next time that function
is called, a new alias is created.
**Examples**
```
function f()
{
static $fs = 1;
echo "\$fs = $fs\n";
++$fs;
}
for ($i = 1; $i <= 3; ++$i)
f();
```
Unlike the local variable equivalent in [§§](#local-variables), function `f` outputs "`$fs
= 1`", "`$fs = 2`", and "`$fs = 3`", as `$fs` retains its value across
calls.
## # Global Variables
**Syntax:**
global-declaration:
global variable-name-list ;
variable-name-list:
expression
variable-name-list , expression
*expression* is defined in [§§](#general-16).
**Constraints:**
Each *expression* must designate a variable name.
**Semantics:**
A global variable is never defined explicitly; instead, it is created
when it is first assigned a value. That may be done at the top level of
a script, or from within a block in which that variable has been
declared (*imported*, that is) using the `global` keyword.
As described in [§§](#predefined-variables),
[`$GLOBALS`](http://www.php.net/manual/en/reserved.variables.globals.php) is
a superglobal ([§§](#general-5)) array whose elements' key/value pairs contain the
name and value, respectively, of each global variable currently defined.
As such, a global variable `gv` can be initialized with the value `v`,
and possibly be created, using the following form of assignment:
`$GLOBALS['gv'] = v`
As `$GLOBALS` is a superglobal, `gv` need not first be the subject of a
*global-declaration*.
A global variable has script scope ([§§](#scope)) and static storage duration
([§§](#storage-duration)). A global variable is a modifiable lvalue.
When a global value is imported into a function, each time the function
is called, that execution is dealing with an alias ([§§](#general)) to that
global variable. If that alias is passed to the `unset` intrinsic
([§§](#unset)), only that alias is destroyed. The next time that function
is called, a new alias is created with the current value of the global
variable.
**Examples**
```
$colors = array("red", "white", "blue");
$GLOBALS['done'] = FALSE;
// -----------------------------------------
$min = 10; $max = 100; $average = NULL;
global $min, $max; // allowed, but serves no purpose
function compute($p)
{
global $min, $max;
global $average;
$average = ($max + $min)/2;
if ($p)
{
global $result;
$result = 3.456; // initializes a global, creating it, if necessary
}
}
compute(TRUE);
echo "\$average = $average\n"; // $average = 55
echo "\$result = $result\n"; // $result = 3.456
// -----------------------------------------
$g = 100;
function f()
{
$v = 'g';
global $$v; // import global $g
...
}
```
## # Instance Properties
These are described in ([§§](#properties)). They have class scope ([§§](#scope)) and
allocated storage duration ([§§](#storage-duration)).
## # Static Properties
These are described in ([§§](#properties)). They have class scope ([§§](#scope)) and static
storage duration ([§§](#storage-duration)).
## # Class and Interface Constants
These are described in [§§](#constants-2) and [§§](#constants-3). They have class or interface
scope ([§§](#scope)) and static storage duration ([§§](#storage-duration)).
# # Predefined Variables
The following variables are automatically available to all scripts:
Variable Name | Description
------------- | -----------
`$argc` | `int`; The number of command-line arguments passed to the script. This is at least 1. (See `$argv` below.)
`$argv` | `array`; An array of `$argc` elements containing the command-line arguments passed to the script as strings. Each element has an `int` key with the keys being numbered sequentially starting at zero through `$argc-1`. `$argv[0]` is the name of the script. It is implementation-defined as to how white space on command lines is handled, whether letter casing is preserved, which characters constitute quotes, or how `$argv[0]`'s string is formatted. As to how command-line arguments are defined, is unspecified.
`$_COOKIE` | `array`; The variables passed to the current script via HTTP Cookies.
`$_ENV` | `array`; A superglobal ([§§](#general-5)) array in which the environment variable names are element keys, and the environment variable value strings are element values. As to how an environment variable is defined, is unspecified.
`$_FILES` | `array`; The items uploaded to the current script via the HTTP POST method.
`$_GET` | `array`; The variables passed to the current script via the URL parameters.
`$GLOBALS` | `array`; A superglobal ([§§](#general-5)) array containing the names of all variables that are currently defined in the global scope of the script. The variable names are the element keys, and the variable values are the element values.
`$_POST` | `array`; The variables passed to the current script via the HTTP POST method.
`$_REQUEST` | `array`; By default contains the contents of `$_COOKIE`, `$_GET`, and `$_POST`.
`$_SERVER` | `array`; Server and execution environment information, such as headers, paths, and script locations. The entries in this array are created by the web server.
`$_SESSION` | `array`; The session variables available to the current script.
# Conversions
# # General
Some operators implicitly convert automatically the values of operands
from one type to another. Explicit conversion is performed using the
cast operator ([§§](#cast-operator)).
If an expression is converted to its own type, the type and value of the
result are the same as the type and value of the expression.
# # Converting to Boolean Type
The [result type] (http://www.php.net/manual/en/language.types.boolean.php#language.types.boolean.casting) is `bool`.
If the source type is `int` or `float`, then if the source value tests equal
to 0, the result value is `FALSE`; otherwise, the result value is `TRUE`.
If the source value is `NULL`, the result value is `FALSE`.
If the source is an empty string or the string "0", the result value is
`FALSE`; otherwise, the result value is `TRUE`.
If the source is an array with zero elements, the result value is `FALSE`;
otherwise, the result value is `TRUE`.
If the source is an object, the result value is `TRUE`.
If the source is a resource, the result value is `TRUE`.
The library function `boolval` (§xx) allows values to be converted to
`bool`.
# # Converting to Integer Type
The [result type](http://www.php.net/manual/en/language.types.integer.php#language.types.integer.casting) is `int`.
If the source type is `bool`, then if the source value is `FALSE`, the
result value is 0; otherwise, the result value is 1.
If the source type is `float`, for the values `INF`, `-INF`, and `NAN`, the
result value is implementation-defined. For all other values, if the
precision can be preserved, the fractional part is rounded towards zero
and the result is well defined; otherwise, the result is undefined.
If the source value is `NULL`, the result value is 0.
If the source is a numeric string or leading-numeric string ([§§](#the-string-type))
having integer format, if the precision can be preserved the result
value is that string's integer value; otherwise, the result is
undefined. If the source is a numeric string or leading-numeric string
having floating-point format, the string's floating-point value is
treated as described above for a conversion from `float`. The trailing
non-numeric characters in leading-numeric strings are ignored. For any
other string, the result value is 0.
If the source is an array with zero elements, the result value is 0;
otherwise, the result value is 1.
If the source is an object, the conversion is invalid.
If the source is a resource, the result is the resource's unique ID.
The library function [`intva`l
(§xx)](http://www.php.net/manual/en/function.intval.php) allows values
to be converted to `int`.
# # Converting to Floating-Point Type
The [result type](http://www.php.net/manual/en/language.types.float.php#language.types.float.casting) is `float`.
If the source type is `int`, if the precision can be preserved the result
value is the closest approximation to the source value; otherwise, the
result is undefined.
If the source is a numeric string or leading-numeric string ([§§](#the-string-type))
having integer format, the string's integer value is treated as
described above for a conversion from `int`. If the source is a numeric
string or leading-numeric string having floating-point format, the
result value is the closest approximation to the string's floating-point
value. The trailing non-numeric characters in leading-numeric strings
are ignored. For any other string, the result value is 0.
If the source is an object, the conversion is invalid.
For sources of all other types, the conversion is performed by first
converting the source value to [`int`](http://www.php.net/manual/en/language.types.integer.php)
([§§](#converting-to-integer-type)) and then to `float`.
If the source is a resource, the result is the resource's unique ID.
The library function `floatval` (§xx) allows values to be converted to
float.
# # Converting to String Type
The [result type](http://www.php.net/manual/en/language.types.string.php#language.types.string.casting) is string.
If the source type is `bool`, then if the source value is `FALSE`, the
result value is the empty string; otherwise, the result value is "1".
If the source type is `int` or `float`, then the result value is a string
containing the textual representation of the source value (as specified
by the library function `sprintf` (§xx)).
If the source value is `NULL`, the result value is an empty string.
If the source is an array, the result value is the string "Array".
If the source is an object, then if that object's class has a
`__toString` method ([§§](#method-__tostring)), the result value is the string returned
by that method; otherwise, the conversion is invalid.
If the source is a resource, the result value is an
implementation-defined string.
The library function `strval` (§xx) allows values to be converted to
string.
# # Converting to Array Type
The [result type](http://www.php.net/manual/en/language.types.array.php#language.types.array.casting) is `array`.
If the source type is `bool`, `int`, `float`, or `string`, the result value is
an array of one element whose type and value is that of the source.
If the source value is `NULL`, the result value is an array of zero
elements.
If the source is an object, the result is
an [array](http://www.php.net/manual/en/language.types.array.php) of
zero or more elements, where the elements are key/value pairs
corresponding to the
[object](http://www.php.net/manual/en/language.types.object.php)'s
instance properties. The order of insertion of the elements into the
array is the lexical order of the instance properties in the
*class-member-declarations* ([§§](#class-members)) list. The key for a private instance
property has the form "\\0*name*\\0*name*", where the first *name* is
the class name, and the second name is the property name. The key for a
protected instance property has the form "\\0\*\\0*name*", where *name*
is that of the property. The key for a public instance property has the
form "*name*", where *name* is that of the property. The value for each
key is that from the corresponding property's initializer, if one
exists, else `NULL`.
If the source is a resource, the result is an array of one element
containing the implementation-defined value of the resource.
# # Converting to Object Type
The [result type](http://www.php.net/manual/en/language.types.object.php#language.types.object.casting) is `object`.
If the source has any type other than object, the result is an instance
of the predefined class `stdClass` ([§§](#class-stdclass)). If the value of the source
is `NULL`, the instance is empty. If the value of the source has a scalar
type and is non-`NULL`, the instance contains a public property called
scalar whose value is that of the source. If the value of the source is
an array, the instance contains a set of public properties whose names
and values are those of the corresponding key/value pairs in the source.
The order of the properties is the order of insertion of the source's
elements.
# Lexical Structure
# # Scripts
A script ([§§](#program-structure)) is an ordered sequence of characters. Typically, a
script has a one-to-one correspondence with a file in a file system, but
this correspondence is not required.
Conceptually speaking, a script is translated using the following steps:
1. Transformation, which converts a script from a particular character
repertoire and encoding scheme into a sequence of 8-bit characters.
2. Lexical analysis, which translates a stream of input characters into
a stream of tokens.
3. Syntactic analysis, which translates the stream of tokens into
executable code.
Conforming implementations must accept scripts encoded with the UTF-8
encoding form (as defined by the Unicode standard), and transform them
into a sequence of characters. Implementations can choose to accept and
transform additional character encoding schemes.
# # Grammars
This specification shows the syntax of the PHP programming language
using two grammars. The *lexical grammar* defines how source
characters are combined to form white space, comments, and tokens. The
*syntactic grammar* defines how the resulting tokens are combined to
form PHP programs.
The grammars are presented using *grammar productions*, with each one
defining a non-terminal symbol and the possible expansions of that
non-terminal symbol into sequences of non-terminal or terminal symbols.
In productions, non-terminal symbols are shown in slanted type *like
this*, and terminal symbols are shown in a fixed-width font `like this`.
The first line of a grammar production is the name of the non-terminal
symbol being defined, followed by one colon for a syntactic grammar
production, and two colons for a lexical grammar production. Each
successive indented line contains a possible expansion of the
non-terminal given as a sequence of non-terminal or terminal symbols.
For example, the production:
single-line-comment::
// input-charactersopt
# input-charactersopt
defines the lexical grammar production *single-line-comment* as being
the terminals `//` or `#`, followed by an optional *input-characters*. Each
expansion is listed on a separate line.
Although alternatives are usually listed on separate lines, when there
is a large number, the shorthand phrase “one of” may precede a list of
expansions given on a single line. For example,
hexadecimal-digit: one of
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F
# # Lexical analysis
# # General
The production *input-file* is the root of the lexical structure for a
script. Each script must conform to this production.
**Syntax:**
input-file::
input-element
input-file input-element
input-element::
comment
white-space
token
*comment* is defined in [§§](#comments); *white-space* is defined in [§§](#white-space), and
*token* is defined in [§§](#tokens).
**Semantics:**
The basic elements of a script are comments, white space, and tokens.
The lexical processing of a script involves the reduction of that script
into a sequence of tokens ([§§](#tokens)) that becomes the input to the
syntactic analysis. Tokens can be separated by white space ([§§](#white-space)) and
delimited comments ([§§](#comments)).
Lexical processing always results in the creation of the longest
possible lexical element. (For example, `$a+++++$b` must be parsed as
`$a++ ++ +$b`, which syntactically is invalid.)
# # Comments
Two forms of comments are supported: *delimited comments* and
*single-line comments*.
**Syntax:**
comment::
single-line-comment
delimited-comment
single-line-comment::
// input-charactersopt
# input-charactersopt
input-characters::
input-character
input-characters input-character
input-character::
Any source character except new-line
new-line::
Carriage-return character (U+000D)
Line-feed character (U+000A)
Carriage-return character (U+000D) followed by line-feed character (U+000A)
delimited-comment::
/* No characters or any source character sequence except /* */
**Semantics:**
Except within a string literal or a comment, the characters /\* start a
delimited comment, which ends with the characters \*/. Except within a
string literal or a comment, the characters // or \# start a single-line
comment, which ends with a new line. That new line is not part of the
comment. However, if the single-line comment is the last source element
in an embedded script, the trailing new line can be omitted. (Note: this
allows for uses like ``.)
A delimited comment can occur in any place in a script in which white
space ([§§](#white-space)) can occur. (For example;
`/*...*/$c/*...*/=/*...*/567/*...*/;/*...*/` is parsed as `$c=567;`, and
`$k = $i+++/*...*/++$j;` is parsed as `$k = $i+++ ++$j;`.)
**Implementation Notes**
During tokenizing, an implementation can treat a delimited comment as
though it was white space.
## # White Space
White space consists of an arbitrary combination of one or more
new-line, space, horizontal tab, vertical tab, and form-feed characters.
**Syntax:**
white-space::
white-space-character
white-space white-space-character
white-space-character::
new-line
Space character (U+0020)
Horizontal-tab character (U+0009)
*new-line* is defined in [§§](#comments).
**Semantics:**
The space and horizontal tab characters are considered *horizontal
white-space characters*.
## # Tokens
### # General
There are several kinds of source *token*s:
**Syntax:**
token::
variable-name
name
keyword
literal
operator-or-punctuator
*variable-name* and *name* are defined in [§§](#names); *keyword* is defined
in [§§](#keywords); *literal* is defined in [§§](#general-9); and
*operator-or-punctuator* is defined in [§§](#operators-and-punctuators).
### # Names
**Syntax:**
variable-name::
$ name
namespace-name::
name
namespace-name \ name
namespace-name-as-a-prefix::
\
\opt namespace-name \
namespace \
namespace \ namespace-name \
qualified-name::
namespace-name-as-a-prefixopt name
name::
name-nondigit
name name-nondigit
name digit
name-nondigit::
nondigit
one of the characters U+007f–U+00ff
nondigit:: one of
_
a b c d e f g h i j k l m
n o p q r s t u v w x y z
A B C D E F G H I J K L M
N O P Q R S T U V W X Y Z
*digit* is defined in [§§](#integer-literals)
**Semantics:**
Names are used to identify the following: constants ([§§](#general-4)), variables
([§§](#general-5)), labels ([§§](#labeled-statements)), functions ([§§](#function-definitions)), classes ([§§](#class-declarations)), class
members ([§§](#class-members)), interfaces ([§§](#interface-declarations)), traits ([§§](#general-26)), namespaces ([§§](#general-28)),
and names in heredoc ([§§](#heredoc-string-literals)) and nowdoc comments ([§§](#nowdoc-string-literals)).
A *name* begins with an underscore (_), *name-nondigit*, or extended
name character in the range U+007f– ** U+00ff. Subsequent characters can
also include *digit*s. A *variable name* is a name with a leading
dollar ($).
Unless stated otherwise ([§§](#function-definitions), [§§](#class-declarations), [§§](#methods), [§§](#interface-declarations), [§§](#trait-declarations), [§§](#defining-namespaces)),
names are case-sensitive, and every character in a name is significant.
Function and method names beginning with two underscores (__) are
reserved by the PHP language.
Variable names and function names (when used in a function-call context)
need not be defined as source tokens; they can also be created at
runtime using the variable name-creation operator ([§§](#variable-name-creation-operator)). (For
example, given `$a = "Total"; $b = 3; $c = $b + 5;, ${$a.$b.$c} =
TRUE;` is equivalent to `$Total38 = TRUE;`, and `${$a.$b.$c}()` is
equivalent to `Total38()`).
**Examples**
```
const MAX_VALUE = 100;
function getData() { ... }
class Point { ... }
interface ICollection { ... }
```
**Implementation Notes**
An implementation is discouraged from placing arbitrary restrictions on
name length or length of significance.
### # Keywords
A *keyword* is a name-like sequence of characters that is reserved, and
cannot be used as a name.
**Syntax:**
keyword:: one of
abstract and as break callable case catch class clone
const continue declare default do echo else elseif
enddeclare endfor endforeach endif endswitch endwhile
extends final finally for foreach function global
goto if implements include include_once instanceof
insteadof interface namespace new or print private
protected public require require_once return static switch
throw trait try use var while xor yield
**Semantics:**
Keywords are not case-sensitive.
### # Literals
#### # General
The source code representation of a value is called a *literal*.
**Syntax:**
literal::
boolean-literal
integer-literal
floating-literal
string-literal
null-literal
*boolean-literal* is defined in [§§](#boolean-literals); *integer-literal* is defined
in [§§](#integer-literals); *floating-literal* is defined in [§§](#floating-point-literals);
*string-literal* is defined in [§§](#string-literals); and *null-literal* is defined
in [§§](#the-null-literal).
#### # Boolean Literals
**Syntax:**
boolean-literal::
TRUE (written in any case combination)
FALSE (written in any case combination)
**Semantics:**
The type of a *boolean-literal* is bool. The values `TRUE` and `FALSE`
represent the Boolean values True and False, respectively.
**Examples**
```
$done = FALSE;
computeValues($table, TRUE);
```
#### # Integer Literals
**Syntax:**
integer-literal::
decimal-literal
octal-literal
hexadecimal-literal
binary-literal
decimal-literal::
nonzero-digit
decimal-literal digit
octal-literal::
0
octal-literal octal-digit
hexadecimal-literal::
hexadecimal-prefix hexadecimal-digit
hexadecimal-literal hexadecimal-digit
hexadecimal-prefix:: one of
0x 0X
binary-literal::
binary-prefix binary-digit
binary-literal binary-digit
binary-prefix:: one of
0b 0B
digit:: one of
0 1 2 3 4 5 6 7 8 9
nonzero-digit:: one of
1 2 3 4 5 6 7 8 9
octal-digit:: one of
0 1 2 3 4 5 6 7
hexadecimal-digit:: one of
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F
binary-digit:: one of
0 1
**Semantics:**
The value of a decimal integer literal is computed using base 10; that
of an octal integer literal, base 8; that of a hexadecimal integer
literal, base 16; and that of a binary integer literal, base 2.
If the value of an *integer-literal* can be represented in type int,
that is its type; otherwise, its type is float, as described below.
Using a twos-complement system, can the smallest negative value
(-2147483648 for 32 bits and -9223372036854775808 for 64 bits) be
represented as a decimal integer literal? No. Consider the
expression -5. This is made up of two tokens: a unary minus followed by
the integer literal 5. As such, **there is no such thing as a
negative-valued decimal integer literal in PHP**. Instead, there is the
non-negative value, which is then negated. However, if the non-negative
value is too large to represent as an `int`, it becomes `float`, which is
then negated. Literals written using hexadecimal, octal, or binary
notations are considered to have non-negative values.
**Examples**
```
$count = 10 // decimal 10
0b101010 >> 4 // binary 101010 and decimal 4
0XAF << 023 // hexadecimal AF and octal 23
```
On an implementation using 32-bit int representation
```
2147483648 -> 2147483648 (too big for int, so is a float)
-2147483648 -> -2147483648 (too big for int, so is a float, negated)
-2147483647 - 1 -> -2147483648 fits in int
0x80000000 -> 2147483648 (too big for int, so is a float)
```
#### # Floating-Point Literals
**Syntax:**
floating-literal::
fractional-literal exponent-partopt
digit-sequence exponent-part
fractional-literal::
digit-sequenceopt . digit-sequence
digit-sequence .
exponent-part::
e signopt digit-sequence
E signopt digit-sequence
sign:: one of
+ -
digit-sequence::
digit
digit-sequence digit
*digit* is defined in [§§](#integer-literals).
**Constraints**
The value of a floating-point literal must be representable by its type.
**Semantics:**
The type of a *floating-literal* is `float`.
The constants `INF` (§[[6.3](#core-predefined-constants)](#core-predefined-constants)) and `NAN` (§[[6.3](#core-predefined-constants)](#core-predefined-constants)) provide access to the floating-
point values for infinity and Not-a-Number, respectively.
**Examples**
```
$values = array(1.23, 3e12, 543.678E-23);
```
#### # String Literals
**Syntax:**
string-literal::
single-quoted-string-literal
double-quoted-string-literal
heredoc-string-literal
nowdoc-string-literal
*single-quoted-string-literal* is defined in [§§](#integer-literals);
*double-quoted-string-literal* is defined in [§§](#integer-literals);
*heredoc-string-literal* is defined in [§§](#integer-literals); and
*nowdoc-string-literal* is defined in [§§](#integer-literals).
Note: By conventional standards, calling *heredoc-string-literal*s (§)
and *nowdoc-string-literal*s ([§§](#nowdoc-string-literals)) literals is a stretch, as
each is hardly a single token.
**Semantics:**
A string literal is a sequence of zero or more characters delimited in
some fashion. The delimiters are not part of the literal's content.
The type of a string literal is string.
##### # Single-Quoted String Literals
**Syntax:**
single-quoted-string-literal::
bopt ' sq-char-sequenceopt '
sq-char-sequence::
sq-char
sq-char-sequence sq-char
sq-char::
sq-escape-sequence
\opt any member of the source character set except single-quote (') or backslash (\)
sq-escape-sequence:: one of
\' \\
**Semantics:**
A single-quoted string literal is a string literal delimited by
single-quotes ('). The literal can contain any source character except
single-quote (') and backslash (\\), which can only be represented by
their corresponding escape sequence.
The optional `b` prefix is reserved for future use in dealing with
so-called *binary strings*. For now, a *single-quoted-string-literal*
with a `b` prefix is equivalent to one without.
A single-quoted string literal is a c-constant ([§§](#general-4)).
**Examples**
```
'This text is taken verbatim'
'Can embed a single quote (\') and a backslash (\\) like this'
```
##### # Double-Quoted String Literals
**Syntax:**
double-quoted-string-literal::
bopt " dq-char-sequenceopt "
dq-char-sequence::
dq-char
dq-char-sequence dq-char
dq-char::
dq-escape-sequence
any member of the source character set except double-quote (") or backslash (\)
\ any member of the source character set except "\$efnrtvxX or
octal-digit
dq-escape-sequence::
dq-simple-escape-sequence
dq-octal-escape-sequence
dq-hexadecimal-escape-sequence
dq-simple-escape-sequence:: one of
\" \\ \$ \e \f \n \r \t \v
dq-octal-escape-sequence::
\ octal-digit
\ octal-digit octal-digit
\ octal-digit octal-digit octal-digit
dq-hexadecimal-escape-sequence::
\x hexadecimal-digit hexadecimal-digitopt
\X hexadecimal-digit hexadecimal-digitopt
*octal-digit* and *hexadecimal-digit* are defined in [§§](#integer-literals).
**Semantics:**
A double-quoted string literal is a string literal delimited by
double-quotes ("). The literal can contain any source character except
double-quote (") and backslash (\\), which can only be represented by
their corresponding escape sequence. Certain other (and sometimes
non-printable) characters can also be expressed as escape sequences.
The optional `b` prefix is reserved for future use in dealing with
so-called *binary strings*. For now, a *double-quoted-string-literal*
with a `b` prefix is equivalent to one without.
An escape sequence represents a single-character encoding, as described
in the table below:
Escape sequence | Character name
--------------- | --------------
\$ | Dollar sign
\" | Double quote
\\ | Backslash
\e | Escape
\f | Form feed
\n | New line
\r | Carriage Return
\t | Horizontal Tab
\v | Vertical Tab
\ooo | 1–3-digit octal digit value ooo
\xhh or \Xhh | 1–2-digit hexadecimal digit value hh
Within a double-quoted string literal, except when recognized as the
start of an escape sequence, a backslash (\\) is retained verbatim.
Within a double-quoted string literal a dollar ($) character not
escaped by a backslash (\\) is handled, as follows:
- If that dollar ($) character plus the character sequence following
spells a longest-possible variable name:
- For a scalar type, that variable name is replaced by the string
representation of that variable's value, if such a variable exists.
This is known as *variable substitution*. If no such variable is
currently defined, the value substituted is the empty string. (For
the purposes of variable substitution, the string representation is
produced as if the library function `sprintf` was used. In the case of
a floating-point value, the conversion specifier used is `%.nG`,
where the precision `n` is implementation-defined.
- For a variable that designates an array, if that variable name is
followed by characters of the form "`[index]`" without any
intervening white space, the variable name and these following
characters are presumed to refer to the corresponding element of
that array, in which case, the value of that element is substituted.
If `index` is itself a variable having scalar type, that variable's
value is substituted. If `index` is an integer literal, it must be a
decimal-integer literal. `index` must not be a character sequence
that itself looks like an array subscript or a class property.
- For a variable that designates an array, but no subscript-like
character sequence follows that variable name, the value substituted
is "Array".
- For a variable that designates an instance of a class, if that
variable name is followed by characters of the form "`->name`"
without any intervening white space, the variable name and these
following characters are presumed to refer to the corresponding
property of that instance, in which case, the value of that property
is substituted.
- Otherwise, the dollar ($) is retained verbatim.
Variable substitution also provides limited support for the evaluation
of expressions. This is done by enclosing an expression in a pair of
matching braces ({...}). The opening brace must be followed immediately by
a dollar ($) without any intervening white space, and that dollar must
begin a variable name. If this is not the case, braces are treated
verbatim. An opening brace ({) cannot be escaped.
A double-quoted string literal is a c-constant ([§§](#general-4)) if it does not
contain any variable substitution.
**Examples**
```
$x = 123;
echo ">\$x.$x"."<"; // → >$x.123<
// -----------------------------------------
$colors = array("red", "white", "blue");
$index = 2;
echo "\$colors[$index] contains >$colors[$index]<\n";
// → $colors[2] contains >blue<
// -----------------------------------------
class C {
public $p1 = 2;
}
$myC = new C();
echo "\$myC->p1 = >$myC->p1<\n"; // → $myC->p1 = >2<
```
##### # Heredoc String Literals
**Syntax:**
heredoc-string-literal::
<<< hd-start-identifier new-line hd-char-sequenceopt new-line hd-end-identifier ;opt new-line
hd-start-identifier::
name
hd-end-identifier::
name
hd-char-sequence::
hd-char
hd-char-sequence hd-char
hd-char::
hd-escape-sequence
any member of the source character set except backslash (\)
\ any member of the source character set except \$efnrtvxX or
octal-digit
hd-escape-sequence::
hd-simple-escape-sequence
dq-octal-escape-sequence
dq-hexadecimal-escape-sequence
hd-simple-escape-sequence:: one of
\\ \$ \e \f \n \r \t \v
*name* is defined in [§§](#names); *new-line* is defined in [§§](#comments); and
*dq-octal-escape-sequence* and *dq-hexadecimal-escape-sequence* are
defined in [§§](#double-quoted-string-literals).
**Constraints**
The start and end identifier must be the same. Only horizontal white
space is permitted between `<<<` and the start identifier. No white
space is permitted between the start identifier and the new-line that
follows. No white space is permitted between the new-line and the end
identifier that follows. Exception for an optional semicolon (`;`), no
characters—not even comments or white space—are permitted between the
end identifier and the new-line that terminates that source line.
**Semantics:**
A heredoc string literal is a string literal delimited by
"`<<< name`" and "`name`". The literal can contain any source
character. Certain other (and sometimes non-printable) characters can
also be expressed as escape sequences.
A heredoc literal supports variable substitution as defined for
double-quoted string literals ([§§](#double-quoted-string-literals)).
A heredoc string literal is a c-constant ([§§](#general-4)) if it does not contain
any variable substitution.
**Examples**
```
$v = 123;
$s = <<< ID
S'o'me "\"t e\txt; \$v = $v"
Some more text
ID;
echo ">$s<";
→ >S'o'me "\"t e xt; $v = 123"
Some more text<
```
##### # Nowdoc String Literals
**Syntax:**
nowdoc-string-literal::
<<< ' hd-start-identifier ' new-line hd-char-sequenceopt new-line hd-end-identifier ;opt new-line
*hd-start-identifier*, *hd-char-sequence*, and *hd-end-identifier* are
defined in [§§](#heredoc-string-literals); and *new-line* is defined in [§§](#comments).
**Constraints**
No white space is permitted between the start identifier and its
enclosing single quotes ('). See also [§§](#heredoc-string-literals).
**Semantics:**
A nowdoc string literal looks like a heredoc string literal
([§§](#heredoc-string-literals)) except that in the former the start identifier name is
enclosed in single quotes ('). The two forms of string literal have the
same semantics and constraints except that a nowdoc string literal is
not subject to variable substitution.
A nowdoc string literal is a c-constant ([§§](#general-4)).
**Examples**
```
$v = 123;
$s = <<< 'ID'
S'o'me "\"t e\txt; \$v = $v"
Some more text
ID;
echo ">$s<\n\n";
→ >S'o'me "\"t e\txt; \$v = $v"
Some more text<
```
#### # The Null Literal
There is one null-literal value, `NULL`. Its spelling is case-insensitive.
(Note: Throughout this specification, the convention is to use all
uppercase.)
null-literal::
NULL (written in any case combination)
A *null-literal* has the null type.
### # Operators and Punctuators
**Syntax**
operator-or-punctuator:: one of
[ ] ( ) { } . -> ++ -- ** * + - ~ !
$ / % << >> < > <= >= == === != !== ^ |
& && || ? : ; = **= *= /= %= += -= .= <<=
>>= &= ^= |= ,
**Semantics:**
Operators and punctuators are symbols that have independent syntactic
and semantic significance. *Operators* are used in expressions to
describe operations involving one or more *operands*, and that yield a
resulting value, produce a side effect, or some combination thereof.
*Punctuators* are used for grouping and separating.
# Expressions
# # General
An *expression* involves one or more terms and zero or more operators.
A *full expression* is an expression that is not part of another
expression.
A *side effect* is an action that changes the state of the execution
environment. (Examples of such actions are modifying a variable, writing
to a device or file, or calling a function that performs such
operations.)
When an expression is evaluated, it produces a result. It might also
produce a side effect. Only a few operators produce side effects. (For
example, given the expression statement ([§§](#expression-statements)) `$v = 10`; the
expression 10 is evaluated to the result 10, and there is no side
effect. Then the assignment operator is executed, which results in the
side effect of `$v` being modified. The result of the whole expression is
the value of `$v` after the assignment has taken place. However, that
result is never used. Similarly, given the expression statement `++$v`;
the expression is evaluated to the result incremented-value-of-`$v`, and
the side effect is that `$v` is actually incremented. Again, the result
is never used.)
The occurrence of value computation and side effects is delimited by
*sequence points*, places in a program's execution at which all the
computations and side effects previously promised are complete, and no
computations or side effects of future operations have yet begun. There
is a sequence point at the end of each full expression. The logical and
([§§](#logical-and-operator-form-1)), logical or (§[[10.15](#logical-inclusive-or-operator-form-1)](#logical-inclusive-or-operator-form-1)), conditional (§[[10.15](#logical-inclusive-or-operator-form-1)](#logical-inclusive-or-operator-form-1)), and function-call
([§§](#function-call-operator)) operators each contain a sequence point. (For example, in the
following series of expression statements, `$a = 10; ++$a; $b = $a;`,
there is sequence point at the end of each full expression, so the
assignment to $a is completed before `$a` is incremented, and the
increment is completed before the assignment to `$b`.)
When an expression contains multiple operators, the *precedence* of
those operators controls the order in which those operators are applied.
(For example, the expression `$a - $b / $c` is evaluated as
`$a - ($b / $c)` because the / operator has higher precedence than the
binary - operator.) The precedence of an operator is determined by the
definition of its associated grammar production.
If an operand occurs between two operators having the same precedence,
the order in which the operations are performed is determined by those
operators' *associativity*. With *left-associative* operators,
operations are performed left-to-right. (For example, `$a + $b - $c` is
evaluated as `($a + $b) - $c.`) With *right-associative* operators,
operations are performed right-to-left. (For example, `$a = $b = $c` is
evaluated as `$a = ($b = $c)`.)
Precedence and associativity can be controlled using *grouping
parentheses*. (For example, in the expression `($a - $b) / $c`, the
subtraction is done before the division. Without the grouping
parentheses, the division would take place first.)
While precedence, associativity, and grouping parentheses control the
order in which operators are applied, they do *not* control the order of
evaluation of the terms themselves. Unless stated explicitly in this
specification, the order in which the operands in an expression are
evaluated relative to each other is unspecified. See the discussion
above about the operators that contain sequence points. (For example, in
the full expression `$list1[$i] = $list2[$i++]`, whether the value
of `$i` on the left-hand side is the old or new `$i`, is unspecified.
Similarly, in the full expression `$j = $i + $i++`, whether the value
of `$i` is the old or new `$i`, is unspecified. Finally, in the full
expression `f() + g() \* h()`, the order in which the three functions are
called, is unspecified.)
**Implementation Notes**
An expression that contains no side effects and whose resulting value is
not used need not be evaluated. For example, the expression statements
`6;, $i + 6;`, and `$i/$j`; are well formed, but they contain no side
effects and their results are not used.
A side effect need not be executed if it can be determined that no other
program code relies on its having happened. (For example, in the cases
of return `$a++`; and return `++$a`;, it is obvious what value must be
returned in each case, but if `$a` is a variable local to the enclosing
function, `$a` need not actually be incremented.
# # Primary Expressions
## # General
**Syntax**
primary-expression:
variable-name
qualified-name
literal
const-expression
intrinsic
anonymous-function-creation-expression
( expression )
$this
*variable-name* and *qualified-name* are defined in [§§](#names); *literal*
is defined in [§§](#general-9); *const-expression* is defined in [§§](#constant-expressions);
*intrinsic* is defined in [§§](#general-12);
*anonymous-function-creation-expression* is defined in [§§](#anonymous-function-creation); and
*expression* is defined in [§§](#script-inclusion-operators).
**Semantics**
When the name of a function is used as an expression without the
function-call operator `()` ([§§](#function-call-operator)), that name is treated as a string
containing that function's name.
The type and value of parenthesized expression are identical to those of
the un-parenthesized expression.
The variable `$this` is predefined inside any instance method or
constructor when that method is called from within an object
context. `$this` is a handle ([§§](#general-2)) that points to the calling object or
to the object being constructed. The type of `$this` is the type of the
class within which the usage of `$this` occurs. However, at run time, the
type of the object referred to by `$this` may be the type of the
enclosing class or any type derived from that class.
## # Intrinsics
### # General
**Syntax**
intrinsic:
array-intrinsic
echo-intrinsic
empty-intrinsic
eval-intrinsic
exit-intrinsic
isset-intrinsic
list-intrinsic
print-intrinsic
unset-intrinsic
*array-intrinsic* is defined in [§§](#array); *echo-intrinsic* is defined
in [§§](#echo); *empty-intrinsic* is defined in [§§](#empty);
*eval-intrinsic* is defined in [§§](#eval); *exit-intrinsic* is defined in
[§§](#exitdie); *isset-intrinsic* is defined in [§§](#isset); *list-intrinsic*
is defined in [§§](#list); *print-intrinsic* is defined in [§§](#print); and
*unset-intrinsic* is defined in [§§](#unset).
**Semantics**
The names in this series of subclauses have special meaning and are
called *intrinsics*, but they are not keywords; nor are they functions.
### # array
**Syntax**
array-intrinsic:
array ( array-initializeropt )
*array-initializer* is defined in [§§](#array-creation-operator).
**Semantics**
This intrinsic creates and initializes an array. It is equivalent to the
array-creation operator `[]` ([§§](#array-creation-operator)).
### # echo
**Syntax**
echo-intrinsic:
echo expression
echo ( expression )
echo expression-list-two-or-more
expression-list-two-or-more:
expression , expression
expression-list-two-or-more , expression
*expression* is defined in [§§](#general-16).
**Constraints**
*expression* must not designate an array nor an instance of a type not
having a `__toString` method ([§§](#method-__tostring)).
**Semantics**
After converting each of its *expression*s' values to strings, if
necessary, `echo` concatenates them in lexical order, and writes the
resulting string to `STDOUT` ([§§](#resource-types)). Unlike `print` ([§§](#print)), it does
not produce a result.
For value substitution in string literals, see [§§](#double-quoted-string-literals) and
[§§](#heredoc-string-literals). For conversion to string, see [§§](#converting-to-string-type).
**Examples**
```
$v1 = TRUE;
$v2 = 123;
echo '>>' . $v1 . '|' . $v2 . "<<\n"; // outputs ">>1|123<<"
echo '>>' , $v1 , '|' , $v2 , "<<\n"; // outputs ">>1|123<<"
echo ('>>' . $v1 . '|' . $v2 . "<<\n"); // outputs ">>1|123<<"
$v3 = "qqq{$v2}zzz";
echo "$v3\n";
```
### # empty
**Syntax**
empty-intrinsic:
empty ( expression )
*expression* is defined in [§§](#general-16).
**Semantics**
This intrinsic returns `TRUE` if the variable or value designated by
*expression* is empty, where *empty* means that the variable does not
exist, or it exists and its value compares equal to `FALSE`. Otherwise,
the intrinsic returns `FALSE`.
The following values are considered empty: `FALSE`, `0`, `0.0`, "", "`0`", `NULL`, `[]`/`array()`, and any uninitialized variable.
If this intrinsic is used with an expression that designate a dynamic
property ([§§](#dynamic-members)), then if the class of that property has an `__isset`
method ([§§](#method-__isset)), that method is called.
**Examples**
```
empty("0") // results in TRUE
empty("00") // results in FALSE
$v = [10, 20];
empty($v) // results in FALSE
```
### # eval
**Syntax**
eval-intrinsic:
eval ( expression )
*expression* is defined in [§§](#general-16).
**Constraints**
*expression* must designate a string, the contents of which must be
valid PHP source code.
The PHP source code in the string must not be delimited by opening and
closing [PHP
tags](http://us3.php.net/manual/en/language.basic-syntax.phpmode.php).
**Semantics**
This intrinsic evaluates the contents of the string designated by
*expression*, as PHP source code.
Execution of a `return` statement ([§§](#the-return-statement)) from within the source code
terminates the intrinsic, and the value returned becomes the value
returned by eval. If the source code is ill formed, eval returns `FALSE`;
otherwise, eval returns `NULL`.
The source code is executed in the scope of that from which `eval` is
called.
**Examples**
```
$str = "Hello";
eval("echo \$str . \"\\n\";"); // → echo $str . "\n";
```
### # exit/die
**Syntax**
exit-intrinsic:
exit expressionopt
exit ( expressionopt )
die expressionopt
die ( expressionopt )
*expression* is defined in [§§](#general-16).
**Constraints**
When *expression* designates an integer, its value must be in the range
0–254.
**Semantics**
`exit` and `die` are equivalent.
This intrinsic terminates the current script. If *expression* designates
a string, that string is written to `STDOUT` ([§§](#resource-types)). If *expression*
designates an integer, that represents the script's *exit status code*.
Code 255 is reserved by PHP. Code 0 represents "success". The exit
status code is made available to the execution environment. If
*expression* is omitted or is a string, the exit status code is zero.
`exit` does not have a resulting value.
`exit` performs the following operations, in order:
- Writes the optional string to `STDOUT` ([§§](#resource-types)).
- Calls any functions registered via the library function
`register_shutdown_function` (§xx) in their order of registration.
- Invokes destructors ([§§](#destructors)) for all remaining instances.
**Examples**
```
exit ("Closing down");
exit (1);
exit;
```
### # isset
**Syntax**
isset-intrinsic:
isset ( expression-list-one-or-more )
expression-list-one-or-more:
expression
expression-list-one-or-mor , expression
*expression* is defined in [§§](#general-16).
**Constraints**
Each *expression* must designate a variable.
**Semantics**
This intrinsic returns `TRUE` if all the variables designated by
*expression*s are set and their values are not `NULL`. Otherwise, it
returns `FALSE`.
If this intrinsic is used with an expression that designates a dynamic
property ([§§](#dynamic-members)), then if the class of that property has an `__isset`
method ([§§](#method-__isset)), that method is called.
**Examples**
```
$v = TRUE;
isset($v) // results in TRUE
$v = NULL;
isset($v) // results in FALSE
$v1 = TRUE; $v2 = 12.3; $v1 = NULL;
isset($v1, $v2, $v3) // results in FALSE
```
### # list
**Syntax**
list-intrinsic:
list ( list-expression-listopt )
list-expression-list:
list-or-variable
,
list-expression-list , list-or-variableopt
list-or-variable:
list-intrinsic
expression
*expression* is defined in [§§](#general-16).
**Constraints**
*list-intrinsic* must be used as the left-hand operand in a
*simple-assignment-expression* ([§§](#simple-assignment)) of which the right-hand
operand must be an expression that designates an array (the "source
array").
Each *expression* in *expression-list-one-or-more* must designate a
variable (the "target variable").
**Semantics**
This intrinsic assigns zero or more elements of the source array to the
target variables. On success, it returns a copy of the source array. If
the source array is actually the value `NULL`, this is consider a failure,
and the return value from `list` is undefined.
All elements in the source array having keys of type `string` are ignored.
The element having an `int` key of 0 is assigned to the first target
variable, the element having an `int` key of 1 is assigned to the second
target variable, and so on, until all target variables have been
assigned. Any elements having an `int` key outside the range 0–(*n*-1),
where *n* is the number of target variables, are ignored. If there are
fewer element candidates having int keys than there are target
variables, the unassigned target variables are unset ([§§](#unset)).
Any target variable may be a list, in which case, the corresponding
element is expected to be an array.
If the source array elements and the target variables overlap in any
way, the behavior is unspecified.
**Examples**
```
list($min, $max, $avg) = array(0, 100, 67);
// $min is 0, $max is 100, $avg is 67
list($min, $max, $avg) = array(2 => 67, 1 => 100, 0 => 0);
// same as example above
list($min, , $avg) = array(0, 100, 67);
// $min is 0, $avg is 67
list($min, $max, $avg) = array(0, 2 => 100, 4 => 67);
// $min is 0, $max is unset, $avg is 100
list($min, list($max, $avg)) = [0, [1 => 67, 99, 0 => 100], 33];
// $min is 0, $max is 100, $avg is 67
```
### # print
**Syntax**
print-intrinsic:
print expression
print ( expression )
*expression* is defined in [§§](#general-16).
**Constraints**
*expression* must not designate an array or an instance of a type not
having a `__toString` method.
**Semantics**
After converting its *expression*'s value to a string, if necessary,
`print` writes the resulting string to `STDOUT` ([§§](#resource-types)). Unlike `echo`
([§§](#echo)), `print` can be used in any context allowing an expression. It
always returns the value 1.
For value substitution in string literals, see [§§](#double-quoted-string-literals) and
[§§](#heredoc-string-literals). For conversion to string, see [§§](#converting-to-string-type).
**Examples**
```
$v1 = TRUE;
$v2 = 123;
print '>>' . $v1 . '|' . $v2 . "<<\n"; // outputs ">>1|123<<"
print ('>>' . $v1 . '|' . $v2 . "<<\n"); // outputs ">>1|123<<"
$v3 = "qqq{$v2}zzz";
print "$v3\n"; // outputs "qqq123zzz"
$a > $b ? print "..." : print "...";
```
### # unset
**Syntax**
unset-intrinsic:
unset ( expression-list-one-or-more )
*expression-list-one-or-more* is defined in [§§](#isset).
**Constraints**
Each *expression* must designate a variable.
**Semantics**
This intrinsic unsets ([§§](#general-5)) the variables designated by each
*expression* in *expression-list-one-or-more*. No value is returned. An
attempt to unset a non-existent variable (such as a non-existent element
in an array) is ignored.
When called from inside a function, this intrinsic behaves, as follows:
- For a variable declared `global` in that function, `unset` removes the
alias to that variable from the scope of the current call to that
function. Once the function returns, the global variable is still
set. (To unset the global variable, use unset on the corresponding
[`$GLOBALS`](http://us3.php.net/manual/en/reserved.variables.globals.php) array entry ([§§](#predefined-variables)).)
- For a variable passed byRef to that function, `unset` removes the
alias to that variable from the scope of the current call to that
function. Once the function returns, the passed-in argument variable
is still set.
- For a variable declared static in that function, `unset` removes the
alias to that variable from the scope of the current call to that
function. In subsequent calls to that function, the static variable
is still set and retains its value from call to call.
Any visible instance property may be unset, in which case, the property
is removed from that instance.
If this intrinsic is used with an expression that designate a dynamic
property ([§§](#dynamic-members)), then if the class of that property has an `__unset`
method ([§§](#method-__unset)), that method is called.
**Examples**
```
unset($v);
unset($v1, $v2, $v3);
unset($x->m); // if m is a dynamic property, $x's __unset("m") is called
```
## # Anonymous Function-Creation
**Syntax**
anonymous-function-creation-expression:
function &opt ( parameter-declaration-listopt ) anonymous-function-use-clauseopt
compound-statement
anonymous-function-use-clause:
use ( use-variable-name-list )
use-variable-name-list:
&opt variable-name
use-variable-name-list , &opt variable-name
*parameter-declaration-list* is defined in [§§](#function-definitions); *compound-statement*
is defined in [§§](#compound-statements); *variable-name* is defined in [§§](#names).
**Semantics**
This operator returns an object of type `Closure` ([§§](#class-closure)), or a derived
type thereof, that encapsulates the anonymous function ([§§](#anonymous-functions)) defined
within. An anonymous function is defined like, and behaves like, a named
function ([§§](#function-definitions)) except that the former has no name and has an optional
*anonymous-function-use-clause*.
An expression that designates an anonymous function is compatible with
the type hint `callable` ([§§](#function-definitions)).
The *use-variable-name-list* is a list of variables from the enclosing
scope, which are to be made available by name to the body of the
anonymous function. Each of these may be passed by value or byRef, as
needed. The values used for these variables are those at the time the
`Closure` object is created, not when it is used to call the function it
encapsulates.
An anonymous function defined inside an instance method has access to
the variable `$this`.
**Examples**
```
function doit($value, callable $process) // return type is "Closure"
{
return $process($value);
}
$result = doit(5, function ($p) { return $p * 2; }); // doubles a value
$result = doit(5, function ($p) { return $p * $p; }); // squares a value
// -----------------------------------------
class C
{
public function compute(array $values)
{
$count = 0;
$callback1 = function () use (&$count) // called C::{closure}
{
++$count;
...
};
...
$callback2 = function() // also called C::{closure}
{
...
};
...
}
...
}
```
# # Postfix Operators
## # General
**Syntax**
postfix-expression:
primary-expression
clone-expression
object-creation-expression
array-creation-expression
subscript-expression
function-call-expression
member-selection-expression
postfix-increment-expression
postfix-decrement-expression
scope-resolution-expression
exponentiation-expression
*primary-expression* is defined in [§§](#general-11); *clone-expression* is
defined in [§§](#the-clone-operator); *object-creation-expression* is defined in [§§](#the-new-operator);
*array-creation-expression* is defined in [§§](#array-creation-operator);
*subscript-expression* is defined in [§§](#subscript-operator); *function-call-expression* is defined in [§§](#function-call-operator); *member-selection-expression* is defined in [§§](#member-selection-operator);
*postfix-increment-expression* and *postfix-decrement-expression* are
defined in [§§](#postfix-increment-and-decrement-operators); *scope-resolution-expression* is defined in [§§](#scope-resolution-operator);
and *exponentiation-expression* is defined in [§§](#exponentiation-operator)..
**Semantics**
These operators associate left-to-right.
## # The `clone` Operator
**Syntax**
clone-expression:
clone expression
*expression* is defined in [§§](#general-16).
**Constraints**
*expression* must designate an object.
**Semantics**
The `clone` operator creates a new object that is a shallow copy of the object designated by *expression*. Then, if the class type of *expression* has a method called `__clone` ([§§](#method-__clone)), that is called to perform a deep copy. The result is a handle that points to the new object.
**Examples**
Consider a class `Employee`, from which is derived a class `Manager`. Let us
assume that both classes contain properties that are objects. clone is
used to make a copy of a Manager object, and behind the scenes, the
`Manager` object uses clone to copy the properties for the base class,
`Employee`.
```
class Employee
{
...
public function __clone()
{
// make a deep copy of Employee object
}
}
class Manager extends Employee
{
...
public function __clone()
{
$v = parent::__clone();
// make a deep copy of Manager object
}
}
$obj1 = new Manager("Smith", 23);
$obj2 = clone $obj1; // creates a new Manager that is a deep copy
```
## # The `new` Operator
**Syntax**
object-creation-expression:
new class-type-designator ( argument-expression-listopt )
new class-type-designator
class-type-designator:
static
qualified-name
expression
*argument-expression-list* is defined in [§§](#function-call-operator); *qualified-name* is
defined in [§§](#names); and *expression* is defined in [§§](#general-16).
**Constraints**
*qualified-name* must name a class.
*expression* must be a value of type `string` (but not be a string
literal) that contains the name of a class.
*class-type-designator* must not designate an abstract class ([§§](#general-23)).
The number of arguments in *argument-expression-list* must be at least
as many as the number of parameters defined for the class's constructor.
**Semantics**
The `new` operator allocates memory for an object that is an instance of
the class specified by *class-type-designator*.
The object is initialized by calling the class's constructor ([§§](#constructors))
passing it the optional *argument-expression-list*. If the class has no
constructor, the constructor that class inherits (if any) is used.
Otherwise, each instance property takes on the value `NULL`.
The result of an *object-creation-expression* is a handle to an object
of the type specified by *class-type-designator*.
From within a method, the use of `static` corresponds to the class in the
inheritance context in which the method is called.
Because a constructor call is a function call, the relevant parts of
[§§](#function-call-operator) also apply.
**Examples**
```
class Point
{
public function __construct($x = 0, $y = 0)
{
...
}
...
}
$p1 = new Point; // create Point(0, 0)
$p1 = new Point(12); // create Point(12, 0)
$cName = 'Point';
$p1 = new $cName(-1, 1); // create Point(-1, 1)
```
## # Array Creation Operator
An array is created and initialized by one of two equivalent ways: via
the array-creation operator `[]`, as described below, or the intrinsic
`array` ([§§](#array)).
**Syntax**
array-creation-expression:
array ( array-initializeropt )
[ array-initializeropt ]
array-initializer:
array-initializer-list ,opt
array-initializer-list:
array-element-initializer
array-element-initializer , array-initializer-list
array-element-initializer:
&opt element-value
element-key => &opt element-value
element-key:
expression
element-value
expression
*expression* is defined in [§§](#general-16).
**Constraints**
If *array-element-initializer* contains &, *element-value's expression*
must be a variable name ([§§](#names)).
**Semantics**
If *array-initializer* is omitted, the array has zero elements. For
convenience, an *array-initializer* may have a trailing comma; however,
this comma has no purpose. An *array-initializer-list* consists of a
comma-separated list of one or more *array-element-initializer*s, each
of which is used to provide an *element-value* and an optional
*element-key*.
If the value of *element-key* is neither `int` nor `string`, keys with `float`
or `bool` values, or strings whose contents match exactly the pattern of
*decimal-literal* ([§§](#integer-literals)), are converted to `int` ([§§](#converting-to-integer-type)), and values
of all other key types are converted to `string` ([§§](#converting-to-string-type)).
If *element-key* is omitted from an *array-element-initializer*, an
element key of type `int` is associated with the corresponding
*element-value*. The key associated is one more than the previously
assigned `int` key for this array, regardless of whether that key was
provided explicitly or by default. However, if this is the first element
with an `int` key, key zero is associated.
Once the element keys have been converted to `int` or `string`, and omitted
element keys have each been associated by default, if two or more
*array-element-initializer*s in an *array-initializer* contain the same
key, the lexically right-most one is the one whose element-value is used
to initialize that element.
The result of this operator is a handle to the set of array elements.
If *array-element-initializer* contains &, *element-value's* value is
stored using byRef assignment ([§§](#assignment)).
**Examples**
```
$v = []; // array has 0 elements
$v = array(TRUE); // array has 1 element, the Boolean TRUE
$v = [123, -56]; // array of two ints, with implicit int keys 0 and 1
$v = [0 => 123, 1 => -56]; // array of two ints, with explicit int keys 0 and 1
$i = 10;
$v = [$i - 10 => 123, $i - 9 => -56]; // key can be a runtime expression
$v = [NULL, 1 => FALSE, 123, 3 => 34e12, "Hello"]; // implicit & explicit keys
$i = 6; $j = 12;
$v = [7 => 123, 3 => $i, 6 => ++$j]; // keys are in arbitrary order
$v[4] = 99; // extends array with a new element
$v = [2 => 23, 1 => 10, 2 => 46, 1.9 => 6];
// array has 2, with keys 2 and 1, values 46 and 6, respectively
$v = ["red" => 10, "4" => 3, 9.2 => 5, "12.8" => 111, NULL => 1];
// array has 5 elements, with keys “red”, 4, 9, “12.8”, and “”.
$c = array("red", "white", "blue");
$v = array(10, $c, NULL, array(FALSE, NULL, $c));
$v = array(2 => TRUE, 0 => 123, 1 => 34.5, -1 => "red");
foreach($v as $e) { ... } // iterates over keys 2, 0, 1, -1
for ($i = -1; $i <= 2; ++$i) { ... $v[$i] } // retrieves via keys -1, 0, 1, 2
```
## # Subscript Operator
**Syntax**
subscript-expression:
postfix-expression [ expressionopt ]
postfix-expression { expressionopt } [Deprecated form]
*postfix-expression* is defined in [§§](#general-13); and *expression* is defined
in [§§](#general-16).
**Constraints**
If *postfix-expression* designates a string, *expression* must not
designate a string.
*expression* can be omitted only if *subscript-expression* is used in a
modifiable-lvalue context and *postfix-expression* does not designate a
string.
If *subscript-expression* is used in a non-lvalue context, the element
being designated must exist.
**Semantics**
A *subscript-expression* designates a (possibly non-existent) element of
an array or string. When *subscript-expression* designates an object of
a type that implements `ArrayAccess` ([§§](#interface-arrayaccess)), the minimal semantics are
defined below; however, they can be augmented by that object's methods
`offsetGet` (§[[15.6.1](#interface-arrayaccess)](#interface-arrayaccess)) and `offsetSet` (§[[15.6.1](#interface-arrayaccess)](#interface-arrayaccess)).
The element key is designated by *expression*. If the value of
*element-key* is neither `int` nor `string`, keys with `float` or `bool` values,
or strings whose contents match exactly the pattern of *decimal-literal*
([§§](#integer-literals)), are converted to `int` ([§§](#converting-to-integer-type)), and values of all other key
types are converted to `string` ([§§](#converting-to-string-type)).
If both *postfix-expression* and *expression* designate strings,
*expression* is treated as if it specified the `int` key zero instead.
A *subscript-expression* designates a modifiable lvalue if and only if
*postfix-expression* designates a modifiable lvalue.
*postfix-expression designates an array*
If *expression* is present, if the designated element exists, the type
and value of the result is the type and value of that element;
otherwise, the result is `NULL`.
If *expression* is omitted, a new element is inserted. Its key has type
`int` and is one more than the highest, previously assigned, non-negative
`int` key for this array. If this is the first element with a non-negative
`int` key, key zero is used. However, if the highest, previously assigned
`int` key for this array is `PHP_INT_MAX` ([§§](#)), **no new element is
inserted**. The type and value of the result is the type and value of
the new element.
- If the usage context is as the left-hand side of a
*simple-assignment-expression* ([§§](#simple-assignment)): The value of the new
element is the value of the right-hand side of that
*simple-assignment-expression*.
- If the usage context is as the left-hand side of a
*compound-assignment-expression* ([§§](#compound-assignment)): The expression
`e1 op= e2` is evaluated as `e1 = NULL op (e2)`.
- If the usage context is as the operand of a postfix- or
prefix-increment or decrement operator ([§§](#postfix-increment-and-decrement-operators), [§§](#prefix-increment-and-decrement-operators)): The value
of the new element is `NULL`.
*postfix-expression designates a string*
If the designated element exists, the type and value of the result is
the type and value of that element; otherwise, the result is an empty
string.
*postfix-expression designates an object of a type that implements*
`ArrayAccess`
If *expression* is present,
- If *subscript-expression* is used in a non-lvalue context, the
object's method `offsetGet` is called with an argument of
*expression*. The type and value of the result is the type and value
returned by `offsetGet`.
- If the usage context is as the left-hand side of a
*simple-assignment-expression*: The object's method `offsetSet` is
called with a first argument of *expression* and a second argument
that is the value of the right-hand side of that
*simple-assignment-expression*. The type and value of the result is
the type and value of the right-hand side of that
*simple-assignment-expression*.
- If the usage context is as the left-hand side of a
*compound-assignment-expression*: The expression `e1 op= e2` is
evaluated as `e1 = offsetGet(expression) op (e2)`, which is then
processed according to the rules for simple assignment immediately
above.
- If the usage context is as the operand of a postfix- or
prefix-increment or decrement operator ([§§](#postfix-increment-and-decrement-operators), [§§](#prefix-increment-and-decrement-operators)): The
object's method `offsetGet` is called with an argument of
*expression*. However, this method has no way of knowing if an
increment or decrement operator was used, or whether it was a prefix
or postfix operator. The type and value of the result is the type
and value returned by `offsetGet`.
If *expression* is omitted,
- If the usage context is as the left-hand side of a
*simple-assignment-expression*: The object's method `offsetSet`
([§§](#interface-arrayaccess)) is called with a first argument of `NULL` and a second
argument that is the value of the right-hand side of that
*simple-assignment-expression*. The type and value of the result is
the type and value of the right-hand side of that
*simple-assignment-expression*.
- If the usage context is as the left-hand side of a
*compound-assignment-expression*: The expression `e1 op= e2` is
evaluated as `e1 = offsetGet(NULL) op (e2)`, which is then processed
according to the rules for simple assignment immediately above.
- If the usage context is as the operand of a postfix- or
prefix-increment or decrement operator ([§§](#postfix-increment-and-decrement-operators), [§§](#prefix-increment-and-decrement-operators)): The
object's method `offsetGet` is called with an argument of `NULL`.
However, this method has no way of knowing if an increment or
decrement operator was used, or whether it was a prefix or postfix
operator. The type and value of the result is the type and value
returned by `offsetGet`.
Note: The brace (`{...}`) form of this operator has been deprecated.
**Examples**
```
$v = array(10, 20, 30);
$v[1] = 1.234; // change the value (and type) of element [1]
$v[-10] = 19; // insert a new element with int key -10
$v["red"] = TRUE; // insert a new element with string key "red"
[[2,4,6,8], [5,10], [100,200,300]][0][2] // designates element with value 6
["black", "white", "yellow"][1][2] // designates substring "i" in "white"
function f() { return [1000, 2000, 3000]; }
f()[2] // designates element with value 3000
"red"[1.9] // designates [1]
"red"[0][0][0] // designates [0]
// -----------------------------------------
class MyVector implements ArrayAccess { ... }
$vect1 = new MyVector(array(10, 'A' => 2.3, "up"));
$vect1[10] = 987; // calls Vector::offsetSet(10, 987)
$vect1[] = "xxx"; // calls Vector::offsetSet(NULL, "xxx")
$x = $vect1[1]; // calls Vector::offsetGet(1)
```
## # Function Call Operator
**Syntax**
function-call-expression:
postfix-expression ( argument-expression-listopt )
argument-expression-list:
assignment-expression
argument-expression-list , assignment-expression
*postfix-expression* is defined in [§§](#general-13); and *assignment-expression*
is defined in [§§](#general-15).
**Constraints**
*postfix-expression* must designate a function, either by being its
*name*, by being a value of type string (but not a string literal) that
contains the function's name, or by being a variable whose type is
`Closure` ([§§](#class-closure)) or a derived type thereof.
The number of arguments present in a function call must be at least as
many as the number of parameters defined for that function.
No calls can be made to a conditionally defined function ([§§](#general-22)) until
that function exists.
Any argument that matches a parameter passed byRef should (but need not)
designate an lvalue.
**Semantics**
An expression of the form *function-call-expression* is a *function
call*. The postfix expression designates the *called function*, and
*argument-expression-list* specifies the arguments to be passed to that
function. An argument can have any type. In a function call,
*postfix-expression* is evaluated first, followed by each
*assignment-expression* in the order left-to-right. There is a sequence
point ([§§](#general-10)) right before the function is called. For details of the
type and value of a function call see [§§](#the-return-statement). The value of a function
call is a modifiable lvalue only if the function returns a byRef that
aliases a modifiable lvalue.
When *postfix-expression* designates an instance method or constructor,
the instance used in that designation is used as the value of `$this` in
the invoked method or constructor. However, if no instance was used in
that designation (for example, in the call `C::instance_method()`) the
invoked instance has no `$this` defined.
When a function is called, the value of each argument passed to it is
assigned to the corresponding parameter in that function's definition,
if such a parameter exists. The assignment of argument values to
parameters is defined in terms of simple ([§§](#simple-assignment)) or byRef assignment
([§§](#byref-assignment)), depending on how the parameter was declared. There may be
more arguments than parameters, in which case, the library functions
[`func_num_args`](http://www.php.net/manual/en/function.func-num-args.php)
(§xx), [`func_get_arg`](http://www.php.net/manual/en/function.func-get-arg.php)
(§xx),
and [`func_get_args`](http://www.php.net/manual/en/function.func-get-args.php)
(§xx) can be used to get access to the complete argument list that was
passed. If the number of arguments present in a function call is fewer
than the number of parameters defined for that function, any parameter
not having a corresponding argument is considered undefined if it has no
default argument value ([§§](#function-definitions)); otherwise, it is considered defined with
that default argument value.
If an undefined variable is passed using byRef, that variable becomes
defined, with a default value of `NULL`.
Direct and indirect recursive function calls are permitted.
If *postfix-expression* is a string, this is a variable function call
([§§](#variable-functions)).
**Examples**
'''
function square($v) { return $v * $v; }
square(5) // call square directly; it returns 25
$funct = square; // assigns the string "square" to $funct
$funct(-2.3) // call square indirectly; it returns 5.29
strlen($lastName) // returns the # of bytes in the string
// -----------------------------------------
function f1() { ... } function f2() { ... } function f3() { ... }
for ($i = 1; $i <= 2; ++$i) { $f = 'f' . $i; $f(); }
// -----------------------------------------
function f($p1, $p2, $p3, $p4, $p5) { ... }
function g($p1, $p2, $p3, $p4, $p5) { ... }
function h($p1, $p2, $p3, $p4, $p5) { ... }
$funcTable = array(f, g, h); // list of 3 function designators
$i = 1;
$funcTable[$i++]($i, ++$i, $i, $i = 12, --$i); // calls g(2,3,3,12,11)
// -----------------------------------------
function f4($p1, $p2 = 1.23, $p3 = "abc") { ... }
f4(); // inside f4, $p1 is undefined, $p2 is 1.23, $p3 is "abc"
// -----------------------------------------
function f(&$p) { ... }
$a = array(10, 20, 30);
f($a[5]); // non-existent element going in, but element exists afterwards
// -----------------------------------------
function factorial($int) // contains a recursive call
{
return ($int > 1) ? $int * factorial($int - 1) : $int;
}
// -----------------------------------------
$anon = function () { ... }; // store a Closure in $anon
$anon(); // call the anonymous function encapsulated by that object
'''
## # Member-Selection Operator
**Syntax**
member-selection-expression:
postfix-expression -> member-selection-designator
member-selection-designator:
name
expression
*postfix-expression* is defined in [§§](#general-13); *name* is defined in
[§§](#names); and *expression* is defined in [§§](#general-16).
**Constraints**
*postfix-expression* must designate an object or be `NULL`, `FALSE`, or an
empty string.
*name* must designate an instance property, or an instance or static
method of *postfix-expression*'s class type.
*expression* must be a value of type `string` (but not a string literal)
that contains the name of an instance property (**without** the
leading `$`) or an instance or static method of that instance's class
type.
**Semantics**
A *member-selection-expression* designates an instance property or an
instance or static method of the object designated by
*postfix-expression*. For a property, the value is that of the property,
and is a modifiable lvalue if *postfix-expression* is a modifiable
lvalue.
When the `->` operator is used in a modifiable lvalue context and *name*
or *expression* designate a property that is not visible, the property
is treated as a dynamic property ([§§](#dynamic-members)). If *postfix-expression*'s class
type defines a `__set` method ([§§](#method-__set)), it is called to store the
property's value. When the `->` operator is used in a non-lvalue context
and *name* or *expression* designate a property that is not visible, the
property is treated as a dynamic property. If *postfix-expression*'s
class type defines a `__get` method ([§§](#method-__get)), it is called to retrieve
the property's value.
If *postfix-expression* is `NULL`, `FALSE`, or an empty string, an expression
of the form `$p->x = 10` causes an instance of `stdClass` ([§§](#class-stdclass)) to be
created with a dynamic property x having a value of 10. `$p` is then made
to refer to this instance.
**Examples**
```
class Point
{
private $x;
private $y;
public function move($x, $y)
{
$this->x = $x; // sets private property $x
$this->y = $y; // sets private property $x
}
public function __toString()
{
return '(' . $this->x . ',' . $this->y . ')';
} // get private properties $x and $y
public function __set($name, $value) { ... }
public function __get($name) { ... }
}
$p1 = new Point;
$p1->move(3, 9); // calls public instance method move by name
$n = "move";
$p1->$n(-2, 4); // calls public instance method move by variable
$p1->color = "red"; // turned into $p1->__set("color", "red");
$c = $p1->color; // turned into $c = $p1->__get("color");
```
## # Postfix Increment and Decrement Operators
**Syntax**
postfix-increment-expression:
unary-expression ++
postfix-decrement-expression:
unary-expression --
*unary-expression* is defined in [§§](#general-14).
**Constraints**
The operand of the postfix ++ and -- operators must be a modifiable
lvalue that has scalar type.
**Semantics**
These operators behave like their prefix counterparts ([§§](#prefix-increment-and-decrement-operators)) except
that the value of a postfix ++ or -- expression is the value before any
increment or decrement takes place.
**Examples**
```
$i = 10; $j = $i-- + 100; // old value of $i (10) is added to 100
$a = array(100, 200); $v = $a[1]++; // old value of $ia[1] (200) is assigned
```
## # Scope-Resolution Operator
**Syntax**
scope-resolution-expression:
scope-resolution-qualifier :: member-selection-designator
scope-resolution-qualifier :: class
scope-resolution-qualifier:
qualified-name
expression
self
parent
static
*member-selection-designator* is defined in [§§](#member-selection-operator).
**Constraints**
*qualified-name* must be the name of a class or interface type.
*expression* must be a value of type string (but not a string literal)
that contains the name of a class or interface type.
**Semantics**
From inside or outside a class or interface, operator `::` allows the
selection of a constant. From inside or outside a class, this operator
allows the selection of a static property, static method, or instance
method. From within a class, it also allows the selection of an
overridden property or method. For a property, the value is that of the
property, and is a modifiable lvalue if *member-selection-designator* is
a modifiable lvalue.
From within a class, `self::m` refers to the member `m` in that class,
whereas `parent::m` refers to the closest member `m` in the base-class
hierarchy, not including the current class. From within a method,
`static::m` refers to the member `m` in the class that corresponds to the
class inheritance context in which the method is called. This allows
*late static binding*. Consider the following scenario:
```
class Base
{
public function b()
{
static::f(); // calls the most appropriate f()
}
public function f() { ... }
}
class Derived extends Base
{
public function f() { ... }
}
$b1 = new Base;
$b1->b(); // as $b1 is an instance of Base, Base::b() calls Base::f()
$d1 = new Derived;
$d1->b(); // as $d1 is an instance of Derived, Base::b() calls Derived::f()
```
The value of the form of *scope-resolution-expression* ending in `::class`
is a string containing the fully qualified name of the current class,
which for a static qualifier, means the current class context.
**Examples**
```
final class MathLibrary
{
public static function sin() { ... }
...
}
$v = MathLibrary::sin(2.34); // call directly by class name
$clName = 'MathLibrary';
$v = $clName::sin(2.34); // call indirectly via string
// -----------------------------------------
class MyRangeException extends Exception
{
public function __construct($message, ...)
{
parent::__construct($message);
...
}
...
}
// -----------------------------------------
class Point
{
private static $pointCount = 0;
public static function getPointCount()
{
return self::$pointCount;
}
...
}
```
## # Exponentiation Operator
**Syntax**
exponentiation-expression:
expression ** expression
*expression* is defined in [§§](#general-16).
**Semantics**
The `**` operator produces the result of raising the value of the
left-hand operand to the power of the right-hand one. If either or both
operands have non-numeric types, their values are converted to type `int`
or `float`, as appropriate. If both operands have non-negative integer
values and the result can be represented as an `int`, the result has type
`int`; otherwise, the result has type `float`.
**Examples**
```
2**3; // int with value 8
2**3.0; // float with value 8.0
"2.0"**"3"; // float with value 8.0
```
# # Unary Operators
## # General
**Syntax**
unary-expression:
postfix-expression
prefix-increment-expression
prefix-decrement-expression
unary-op-expression
error-control-expression
shell-command-expression
cast-expression
variable-name-creation-expression
*postfix-expression* is defined in [§§](#general-13);
*prefix-increment-expression* and *prefix-decrement-expression* are
defined in [§§](#prefix-increment-and-decrement-operators); *unary-op-expression* is defined in [§§](#unary-arithmetic-operators);
*error-control-expression* is defined in [§§](#error-control-operator);
*shell-command-expression* is defined in [§§](#shell-command-operator); *cast-expression* is
defined in [§§](#cast-operator) and *variable-name-creation-expression* is defined in
[§§](#variable-name-creation-operator).
**Semantics**
These operators associate right-to-left.
## # Prefix Increment and Decrement Operators
**Syntax**
prefix-increment-expression:
++ unary-expression
prefix-decrement-expression:
-- unary-expression
*unary-expression* is defined in [§§](#general-14).
**Constraints**
The operand of the prefix `++` or `--` operator must be a modifiable lvalue
that has scalar type.
**Semantics**
*Arithmetic Operands*
For a prefix `++` operator used with an arithmetic operand, the side
effect ([§§](#general-10)) of the operator is to increment by 1, as appropriate, the
value of the operand. The result is the value of the operand after it
has been incremented. If an int operand's value is the largest
representable for that type, the type and value of the result is
implementation-defined ([§§](#the-integer-type)).
For a prefix `--` operator used with an arithmetic operand, the side
effect of the operator is to decrement by 1, as appropriate, the value
of the operand. The result is the value of the operand after it has been
decremented. If an int operand's value is the smallest representable for
that type, the type and value of the result is implementation-defined
([§§](#the-integer-type)).
For a prefix `++` or `--` operator used with an operand having the value
`INF`, `-INF`, or `NAN`, there is no side effect, and the result is the
operand's value.
*Boolean Operands*
For a prefix `++` or `--` operator used with a Boolean-valued operand, there
is no side effect, and the result is the operand's value.
*NULL-valued Operands*
For a prefix -- operator used with a `NULL`-valued operand, there is no
side effect, and the result is the operand's value. For a prefix `++`
operator used with a `NULL`-valued operand, the side effect is that the
operand's type is changed to int, the operand's value is set to zero,
and that value is incremented by 1. The result is the value of the
operand after it has been incremented.
*String Operands*
For a prefix `--` operator used with an operand whose value is an empty
string, the side effect is that the operand's type is changed to `int`,
the operand's value is set to zero, and that value is decremented by 1.
The result is the value of the operand after it has been incremented.
For a prefix `++` operator used with an operand whose value is an empty
string, the side effect is that the operand's value is changed to the
string "1". The type of the operand is unchanged. The result is the new
value of the operand.
For a prefix `--` or `++` operator used with a numeric string, the numeric
string is treated as the corresponding `int` or `float` value.
For a prefix `--` operator used with a non-numeric string-valued operand,
there is no side effect, and the result is the operand's value.
For a non-numeric string-valued operand that contains only alphanumeric
characters, for a prefix `++` operator, the operand is considered to be a
pseudo-base-36 number (i.e., with digits 0–9 followed by A–Z or a–z) in
which letter case is ignored for value purposes. The right-most digit is
incremented by 1. For the digits 0–8, that means going to 1–9. For the
letters "A"–"Y" (or "a"–"y"), that means going to "B"–"Z" (or "b"–"z").
For the digit 9, the digit becomes 0, and the carry is added to the next
left-most digit, and so on. For the digit "Z" (or "z"), the resulting
string has an extra digit "A" (or "a") appended. For example, when
incrementing, "a" -> "b", "X" -> "AA", "AA" -> "AB", "F29" -> "F30", "FZ9" -> "GA0", and "ZZ9" -> "AAA0". A digit position containing a number wraps
modulo-10, while a digit position containing a letter wraps modulo-26.
For a non-numeric string-valued operand that contains any
non-alphanumeric characters, for a prefix `++` operator, all characters up
to and including the right-most non-alphanumeric character is passed
through to the resulting string, unchanged. Characters to the right of
that right-most non-alphanumeric character are treated like a
non-numeric string-valued operand that contains only alphanumeric
characters, except that the resulting string will not be extended.
Instead, a digit position containing a number wraps modulo-10, while a
digit position containing a letter wraps modulo-26.
**Examples**
```
$i = 10; $j = --$i + 100; // new value of $i (9) is added to 100
$a = array(100, 200); $v = ++$a[1]; // new value of $ia[1] (201) is assigned
```
## # Unary Arithmetic Operators
**Syntax**
unary-op-expression:
unary-operator cast-expression
unary-operator: one of
+ - ! \
*cast-expression* is defined in [§§](#cast-operator).
**Constraints**
The operand of the unary `+`, unary `-`, and unary `!` operators must have
scalar type.
The operand of the unary `~` operator must have arithmetic type.
**Semantics**
*Arithmetic Operands*
For a unary `+` operator used with an arithmetic operand, the type and
value of the result is the type and value of the operand.
For a unary `-` operator used with an arithmetic operand, the value of the
result is the negated value of the operand. However, if an int operand's
original value is the smallest representable for that type, the type and
value of the result is implementation-defined ([§§](#the-integer-type)).
For a unary `!` operator used with an arithmetic operand, the type of the
result is `bool`. The value of the result is `TRUE` if the value of the
operand is non-zero; otherwise, the value of the result is `FALSE`. For
the purposes of this operator, `NAN` is considered a non-zero value. The
expression `!E` is equivalent to `(E == 0)`.
For a unary `~` operator used with an `int` operand, the type of the result
is `int`. The value of the result is the bitwise complement of the value
of the operand (that is, each bit in the result is set if and only if
the corresponding bit in the operand is clear). For a unary `~` operator
used with a `float` operand, the value of the operand is first converted
to `int` before the bitwise complement is computed.
*Boolean Operands*
For a unary `+` operator used with a `TRUE`-valued operand, the value of the
result is 1 and the type is `int`. When used with a `FALSE`-valued operand,
the value of the result is zero and the type is `int`.
For a unary `-` operator used with a `TRUE`-valued operand, the value of the
result is -1 and the type is `int`. When used with a `FALSE`-valued operand,
the value of the result is zero and the type is `int`.
For a unary `!` operator used with a `TRUE`-valued operand, the value of the
result is `FALSE` and the type is `bool`. When used with a `FALSE`-valued
operand, the value of the result is `TRUE` and the type is `bool`.
*NULL-valued Operands*
For a unary `+` or unary `-` operator used with a `NULL`-valued operand, the
value of the result is zero and the type is `int`.
For a unary `!` operator used with a `NULL`-valued operand, the value of the
result is `TRUE` and the type is `bool`.
*String Operands*
For a unary `+` or `-` operator used with a numeric string or a
leading-numeric string, the string is first converted to an `int` or
`float`, as appropriate, after which it is handled as an arithmetic
operand. The trailing non-numeric characters in leading-numeric strings
are ignored. With a non-numeric string, the result has type `int` and
value 0.
For a unary `!` operator used with a string, the string is first converted
to `bool`, after which its value is negated.
**Examples**
```
$v = +10;
if ($v1 > -5) ...
$t = TRUE;
if (!$t) ...
$v = ~0b1010101;
```
## # Error Control Operator
**Syntax**
error-control-expression:
@ expression
*expression* is defined in [§§](#general-16).
**Semantics**
Operator `@` supresses any error messages generated by the evaluation of
*expression*.
If a custom error-handler has been established using the library
function [`set_error_handler` (§xx), that
handler](http://us3.php.net/manual/en/function.set-error-handler.php)is
still called.
**Examples**
```
$infile = @fopen("NoSuchFile.txt", 'r');
```
On open failure, the value returned by `fopen` is `FALSE`, which is
sufficient to know to handle the error. There is no need to have any
error message displayed.
**Implementation Notes**
Given the following example:
```
function f() {
$ret = $y;
return $ret;
}
$x = @f(); // without @, get "Undefined variable: y"
```
The following code shows how this statement is handled:
```
$origER = error_reporting();
error_reporting(0);
$tmp = f();
$curER = error_reporting();
if ($curER === 0) error_reporting($origER);
$x = $tmp;
```
## # Shell Command Operator
**Syntax**
shell-command-expression:
` dq-char-sequenceopt `
where \` is the GRAVE ACCENT character U+0060, commonly referred to as a
*backtick*.
*dq-char-sequence* is described in [§§](#double-quoted-string-literals).
**Semantics**
This operator passes *dq-char-sequence* to the command shell for
execution, as though it was being passed to the library function
`shell_exec` (§xx). If the output from execution of that command is
written to `STDOUT` ([§§](#resource-types)), that output is the result of this operator
as a string. If the output is redirected away from `STDOUT`, or
*dq-char-sequence* is empty or contains only white space, the result of
the operator is `NULL`.
If [`shell_exec`](http://www.php.net/manual/en/function.shell-exec.php)
(§xx) is disabled, this operator is disabled.
**Examples**
```
$result = `ls`; // result is the output of command ls
$result = `ls >dirlist.txt`; // result is NULL
$d = "dir"; $f = "*.*";
$result = `$d {$f}`; // result is the output of command dir *.*
```
## # Cast Operator
**Syntax**
cast-expression:
unary-expression
( cast-type ) cast-expression
cast-type: one of
array binary bool boolean double int integer float object
real string unset
*unary-expression* is defined in [§§](#general-14).
**Constraints**
For *binary*, *cast-expression* must designate a string.
**Semantics**
With the exception of the *cast-type*s unset and binary (see below), the
value of the operand *cast-expression* is converted to the type
specified by *cast-type*, and that is the type and value of the result.
This construct is referred to a *cast,* and is used as the verb, "to
cast". If no conversion is involved, the type and value of the result
are the same as those of *cast-expression*.
A cast can result in a loss of information.
A *cast-type* of `array` results in a conversion to type array. See [§§](#converting-to-array-type)
for details.
A *cast-type* of `binary` is reserved for future use in dealing with
so-called *binary strings*. Casting a string to binary results in the
same string.
A *cast-type* of `bool` or `boolean` results in a conversion to type `bool`.
See [§§](#converting-to-boolean-type) for details.
A *cast-type* of `int` or `integer` results in a conversion to type `int`. See [§§](#converting-to-integer-type) for details.
A *cast-type* of `float`, `double`, or `real` results in a conversion to type `float`. See [§§](#converting-to-floating-point-type) for details.
A *cast-type* of `object` results in a conversion to type `object`. See [§§](#converting-to-object-type)
for details.
A *cast-type* of `string` results in a conversion to type `string`. See [§§](#converting-to-string-type)
for details.
A *cast-type* of `unset` always results in a value of `NULL`. (This use of
`unset` should not be confused with the `unset` intrinsic ([§§](#unset)).)
**Examples**
```
(int)(10/3) // results in the int 3 rather than the float 3.333...
(array)(16.5) // results in an array of 1 float; [0] = 16.5
(int)(float)"123.87E3" // results in the int 123870
```
## # Variable-Name Creation Operator
**Syntax**
variable-name-creation-expression:
$ expression
$ { expression }
*expression* is defined in [§§](#general-16).
**Constraints**
In the non-brace form, *expression* must be a
*variable-name-creation-expression* or a *variable-name* that designates
a scalar value.
In the brace form, *expression* must be a
*variable-name-creation-expression* or an expression that designates a
scalar value.
**Semantics**
The result of this operator is a variable name spelled using the textual
representation of the value of *expression* even though such a name
might not be permitted as a variable-name ([§§](#names)) source code token.
This specification documents existing practice rather than ideal
language design, and **there is one aspect of this operator that behaves
in a manner that violates the precedence rules**. Consider `o` to be an
object of some class that has an instance property called `pr`. How is the
non-brace-form expression `$$o->pr` handled with respect to precedence?
As the operator `->` has higher precedence, the answer would seem to be,
"`->` wins over `$`"; however, that is not the case. In fact, the
expression is treated as `${$o}->pr`.
**Examples**
```
$color = "red";
$$color = 123; // equivalent to $red = 123
// -----------------------------------------
$x = 'ab'; $ab = 'fg'; $fg = 'xy';
$$ $ $x = 'Hello'; // equivalent to $xy = Hello
// -----------------------------------------
$v1 = 3;
$$v1 = 22; // equivalent to ${3} = 22
$v2 = 9.543;
$$v2 = TRUE; // equivalent to ${9.543} = TRUE
$v3 = NULL;
$$v3 = "abc"; // equivalent to ${NULL} = "abc"
// -----------------------------------------
function f1 () { return 2.5; }
${1 + f1()} = 1000; // equivalent to ${3.5} = 1000
// -----------------------------------------
$v = array(10, 20); $a = 'v';
$$a[0] = 5; // [] has higher precedence than $
$v = array(10, 20); $a = 'v';
${$a[0]} = 5; // equivalent to above
$v = array(10, 20); $a = 'v';
${$a}[0] = 5; // $ gets first shot at $a
```
# # `instanceof` Operator
**Syntax**
instanceof-expression:
unary-expression
instanceof-subject instanceof instanceof-type-designator
instanceof-subject:
expression
instanceof-type-designator:
qualified-name
expression
*unary-expression* is defined in [§§](#general-14); *expression* is defined in
[§§](#general-16); and *qualified-name* is defined in [§§](#names).
**Constraints**
The *expression* in *instanceof-subject* must designate a variable.
The *expression* in *instanceof-type-designator* must not be any form of
literal.
*qualified-name* must be the name of a class or interface type.
**Semantics**
Operator `instanceof` returns `TRUE` if the variable designated by
*expression* in *instanceof-subject* is an object having type
*qualified-name*, is an object whose type is derived from type
*qualified-name*, or is an object whose type implements interface
*qualified-name*. Otherwise, it returns `FALSE`. When the *expression*
form of *instanceof-type-designator* is used, *expression* may be a
string that contains a class or interface name. Alternatively,
*expression* can designate an instance variable, in which case, operator
`instanceof` returns `TRUE` if the variable designated by the left-hand
*expression* is an instance of the
[`class`](http://www.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class)
type, or of a derived type, of the right-hand *expression*.
If either *expression* is not an instance, `FALSE` is returned.
Note: This operator supersedes the library function `is_a` (§xx), which
has been deprecated.
**Examples**
```
class C1 { ... } $c1 = new C1;
class C2 { ... } $c2 = new C2;
class D extends C1 { ... } $d = new D;
$d instanceof C1 // TRUE
$d instanceof C2 // FALSE
$d instanceof D // TRUE
// -----------------------------------------
interface I1 { ... }
interface I2 { ... }
class E1 implements I1, I2 { ... }
$e1 = new E1;
$e1 instanceof I1 // TRUE
$iName = "I2";
$e1 instanceof $iName // TRUE
```
# # Multiplicative Operators
**Syntax**
multiplicative-expression:
instanceof-expression
multiplicative-expression * multiplicative-expression
multiplicative-expression / multiplicative-expression
multiplicative-expression % multiplicative-expression
*instanceof-expression* is defined in [§§](#instanceof-operator).
**Constraints**
The right-hand operand of operator `/` and operator `%` must not be zero.
**Semantics**
The binary `*` operator produces the product of its operands. If either
or both operands have non-numeric types, their values are converted to
type `int` or `float`, as appropriate. Then if either operand has type
`float`, the other is converted to that type, and the result has type
`float`. Otherwise, both operands have type `int`, in which case, if the
resulting value can be represented in type `int` that is the result type.
Otherwise, the type and value of the result is implementation-defined
([§§](#the-integer-type)).
Division by zero results in a diagnostic followed by a `bool` result
having value `FALSE`. (The values +/- infinity and NaN cannot be generated
via this operator; instead, use the predefined constants `INF` and `NAN`.)
The binary `/` operator produces the quotient from dividing the left-hand
operand by the right-hand one. If either or both operands have
non-numeric types, their values are converted to type `int` or `float`, as
appropriate. Then if either operand has type `float`, the other is
converted to that type, and the result has type `float`. Otherwise, both
operands have type `int`, in which case, if the mathematical value of the
computation can be preserved using type `int`, that is the result type;
otherwise, the type of the result is `float`.
The binary `%` operator produces the remainder from dividing the left-hand
operand by the right-hand one. If the type of both operands is not `int`,
their values are converted to that type. The result has type `int`.
These operators associate left-to-right.
**Examples**
```
-10 * 100; // int with value -1000
100 * -3.4e10; // float with value -3400000000000
"123" * "2e+5; // float with value 24600000
100 / 100; // int with value 1
100 / "123"; // float with value 0.8130081300813
"123" % 100; // int with value 23
```
# # Additive Operators
**Syntax**
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
additive-expression . multiplicative-expression
*multiplicative-expression* is defined in [§§](#multiplicative-operators).
**Constraints**
If either operand has array type, the other operand must also have array
type.
**Semantics**
For non-array operands, the binary `+` operator produces the sum of those
operands, while the binary `- `operator produces the difference of its
operands when subtracting the right-hand operand from the left-hand one.
If either or both operands have non-array, non-numeric types, their
values are converted to type `int` or `float`, as appropriate. Then if
either operand has type `float`, the other is converted to that type, and
the result has type `float`. Otherwise, both operands have type `int`, in
which case, if the resulting value can be represented in type `int` that
is the result type. Otherwise, the type and value of the result is
implementation-defined ([§§](#the-integer-type)).
If both operands have array type, the binary `+` operator produces a new
array that is the union of the two operands. The result is a copy of the
left-hand array with elements inserted at its end, in order, for each
element in the right-hand array whose key does not already exist in the
left-hand array. Any element in the right-hand array whose key exists in
the left-hand array is ignored.
The binary `.` operator creates a string that is the concatenation of the
left-hand operand and the right-hand operand, in that order. If either
or both operands have types other than `string`, their values are
converted to type `string`. The result has type `string`.
These operators associate left-to-right.
**Examples**
```
-10 + 100; // int with value 90
100 + -3.4e10; // float with value -33999999900
"123" + "2e+5"; // float with value 200123
100 - "123"; // int with value 23
-3.4e10 - "abc"; // float with value -34000000000
// -----------------------------------------
[1, 5 => FALSE, "red"] + [4 => -5, 1.23]; // [1, 5 => FALSE, "red", 4 => -5]
// dupe key 5 (value 1.23) is ignored
[NULL] + [1, 5 => FALSE, "red"]; // [NULL, 5 => FALSE, "red"]
// dupe key 0 (value 1) is ignored
[4 => -5, 1.23] + [NULL]; // [4 => -5, 1.23, 0 => NULL]
// -----------------------------------------
-10 . NAN; // string with value "-10NAN"
INF . "2e+5"; // string with value "INF2e+5"
TRUE . NULL; // string with value "1"
10 + 5 . 12 . 100 - 50; // int with value 1512050; ((((10 + 5).12).100)-50)
```
# # Bitwise Shift Operators
**Syntax**
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
*additive-expression* is defined in [§§](#additive-operators).
**Constraints**
Each of the operands must have scalar type.
**Semantics**
Given the expression `e1 << e2`, the bits in the value of `e1` are shifted
left by `e2` positions. Bits shifted off the left end are discarded, and
zero bits are shifted on from the right end. Given the expression
`e1 >> e2`, the bits in the value of `e1` are shifted right by
`e2` positions. Bits shifted off the right end are discarded, and the sign
bit is propagated from the left end.
If either operand does not have type `int`, its value is first converted
to that type.
The type of the result is `int`, and the value of the result is that after
the shifting is complete. The values of `e1` and `e2` are unchanged.
If the shift count is negative, the actual shift applied is `n -
(-shift count % n)`, where `n` is the number of bits per `int`. If the
shift count is greater than the number of bits in an `int`, the actual
shift applied is shift count `% n`.
These operators associate left-to-right.
**Examples**
```
1000 >> 2 // 3E8 is shifted right 2 places
-1000 << 2 // FFFFFC18 is shifted left 5 places
123 >> 128 // adjusted shift count = 0
123 << 33 // For a 32-bit int, adjusted shift count = 1; otherwise, 33
```
# # Relational Operators
**Syntax**
relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression
*shift-expression* is defined in [§§](#bitwise-shift-operators).
**Semantics**
Operator `<` represents *less-than*, operator `>` represents
*greater-than*, operator `<=` represents *less-than-or-equal-to*, and
operator `>=` represents *greater-than-or-equal-to*.
The type of the result is `bool`.
The operands are processed using the following steps, in order:
1. If either operand has the value `NULL`, then if the other operand has
type string, the `NULL` is converted to the empty string ("");
otherwise, the `NULL` is converted to type `bool`.
2. If both operands are non-numeric strings or one is a numeric string
and the other a leading-numeric string, the result is the lexical
comparison of the two operands. Specifically, the strings are
compared byte-by-byte starting with their first byte. If the two
bytes compare equal and there are no more bytes in either string,
the strings are equal and the comparison ends; otherwise, if this is
the final byte in one string, the shorter string compares less-than
the longer string and the comparison ends. If the two bytes compare
unequal, the string having the lower-valued byte compares less-than
the other string, and the comparison ends. If there are more bytes
in the strings, the process is repeated for the next pair of bytes.
3. If either operand has type `bool`, the other operand is converted to
that type. The result is the logical comparison of the two operands
after conversion, where `FALSE` is defined to be less than `TRUE`.
4. If the operands both have arithmetic type, string type, or are
resources, they are converted to the corresponding arithmetic type
([§§](#converting-to-integer-type) and [§§](#converting-to-floating-point-type)). The result is the numerical comparison of the two
operands after conversion.
5. If both operands have array type, if the arrays have different
numbers of elements, the one with the fewer is considered less-than
the other one—regardless of the keys and values in each—, and the
comparison ends. For arrays having the same numbers of elements, if
the next key in the left-hand operand exists in the right-hand
operand, the corresponding values are compared. If they are unequal,
the array containing the lesser value is considered less-than the
other one, and the comparison ends; otherwise, the process is
repeated with the next element. If the next key in the left-hand
operand does not exist in the right-hand operand, the arrays cannot
be compared and `FALSE` is returned. For array comparison, the order
of insertion of the elements into those arrays is irrelevant.
6. If only one operand has object type, that compares greater-than any
other operand type.
7. If only one operand has array type, that compares greater-than any
other operand type.
8. If the operands have different object types, the result is always
`FALSE`.
9. If the operands have the same object type, the result is determined
by comparing the lexically first-declared instance property in each
object. If those properties have object type, the comparison is
applied recursively.
These operators associate left-to-right.
**Examples**
```
"" < "ab" // result has value TRUE
"a" > "A" // result has value TRUE
"a0" < "ab" // result has value TRUE
"aA <= "abc" // result has value TRUE
// -----------------------------------------
NULL < [10,2.3] // result has value TRUE
TRUE > -3.4 // result has value FALSE
TRUE < -3.4 // result has value FALSE
TRUE >= -3.4 // result has value TRUE
FALSE < "abc" // result has value TRUE
// -----------------------------------------
10 <= 0 // result has value FALSE
10 >= "-3.4" // result has value TRUE
"-5.1" > 0 // result has value FALSE
// -----------------------------------------
[100] < [10,20,30] // result has value TRUE (LHS array is shorter)
[10,20] >= ["red"=>0,"green"=>0] // result has value FALSE, (key 10 does not exists in RHS)
["red"=>0,"green"=>0] >= ["green"=>0,"red"=>0] // result has value TRUE (order is irrelevant)
```
# # Equality Operators
**Syntax**
equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
equality-expression <> relational-expression
equality-expression === relational-expression
equality-expression !== relational-expression
*relational-expression* is defined in [§§](#relational-operators).
**Semantics**
Operator `==` represents *value-equality*, operators `!=` and `<>` are
equivalent and represent *value-inequality*, operator `===` represents
*same-type-and-value-equality*, and operator `!==` represents
*not-same-type-and-value-equality*. However, when comparing two objects,
operator `===` represents *identity* and operator `!==` represents
*non-identity*. Specifically, in this context, these operators check to
see if the two operands are the exact same object, not two different
objects of the same type and value.
The type of the result is `bool`.
The operands are processed using the following steps, in order:
1. For operators `==`, `!=`, and `<>`, if either operand has the value
`NULL`, then if the other operand has type string, the `NULL` is
converted to the empty string (""); otherwise, the `NULL` is converted
to type bool.
2. If both operands are non-numeric strings or one is a numeric string
and the other a leading-numeric string, the result is the lexical
comparison of the two operands. Specifically, the strings are
compared byte-by-byte starting with their first byte. If the two
bytes compare equal and there are no more bytes in either string,
the strings are equal and the comparison ends; otherwise, if this is
the final byte in one string, the shorter string compares less-than
the longer string and the comparison ends. If the two bytes compare
unequal, the string having the lower-valued byte compares less-than
the other string, and the comparison ends. If there are more bytes
in the strings, the process is repeated for the next pair of bytes.
3. If either operand has type bool, for operators `==`, `!=`, and `<>`, the
other operand is converted to that type. The result is the logical
comparison of the two operands after any conversion, where `FALSE` is
defined to be less than `TRUE`.
4. If the operands both have arithmetic type, string type, or are
resources, for operators `==`, `!=`, and `<>`, they are converted to the
corresponding arithmetic type ([§§](#converting-to-integer-type) and [§§](#converting-to-floating-point-type)). The result is the
numerical comparison of the two operands after any conversion.
5. If both operands have array type, for operators `==`, `!=`, and `<>`,
the arrays are equal if they have the same set of key/value pairs,
after element type conversion, without regard to the order of
insertion of their elements. For operators `===` and `!==` the arrays
are equal if they have the same set of key/value pairs, the
corresponding values have the same type, and the order of insertion
of their elements are the same.
6. If only one operand has object type, the two operands are never
equal.
7. If only one operand has array type, the two operands are never
equal.
8. If the operands have different object types, the two operands are
never equal.
9. If the operands have the same object type, the two operands are
equal if the instance properties in each object have the same
values. Otherwise, the objects are unequal. The instance properties
are compared, one at a time, in the lexical order of their
declaration. For properties that have object type, the comparison is
applied recursively.
These operators associate left-to-right.
**Examples**
```
"a" <> "aa" // result has value TRUE
// -----------------------------------------
NULL == 0 // result has value TRUE
NULL === 0 // result has value FALSE
TRUE != 100 // result has value FALSE
TRUE !== 100 // result has value TRUE
// -----------------------------------------
"10" != 10 // result has value FALSE
"10" !== 10 // result has value TRUE
// -----------------------------------------
[10,20] == [10,20.0] // result has value TRUE
[10,20] === [10,20.0] // result has value FALSE
["red"=>0,"green"=>0] === ["red"=>0,"green"=>0] // result has value TRUE
["red"=>0,"green"=>0] === ["green"=>0,"red"=>0] // result has value FALSE
```
# # Bitwise AND Operator
**Syntax**
bitwise-AND-expression:
equality-expression
bit-wise-AND-expression & equality-expression
*equality-expression* is defined in [§§](#equality-operators).
**Constraints**
Each of the operands must have scalar type.
**Semantics**
If either operand does not have type `int`, its value is first converted
to that type.
The result of this operator is the bitwise-AND of the two operands, and
the type of that result is `int`.
This operator associates left-to-right.
**Examples**
```
0b101111 & 0b101 // 0b101
$lLetter = 0x73; // letter 's'
$uLetter = $lLetter & ~0x20; // clear the 6th bit to make letter 'S'
```
# # Bitwise Exclusive OR Operator
**Syntax**
bitwise-exc-OR-expression:
bitwise-AND-expression
bitwise-exc-OR-expression ^ bitwise-AND-expression
*bitwise-AND-expression* is defined in [§§](#bitwise-and-operator).
**Constraints**
Each of the operands must have scalar type.
**Semantics**
If either operand does not have type `int`, its value is first converted
to that type.
The result of this operator is the bitwise exclusive-OR of the two
operands, and the type of that result is `int`.
This operator associates left-to-right.
**Examples**
```
0b101111 | 0b101 // 0b101010
$v1 = 1234; $v2 = -987; // swap two integers having different values
$v1 = $v1 ^ $v2;
$v2 = $v1 ^ $v2;
$v1 = $v1 ^ $v2; // $v1 is now -987, and $v2 is now 1234
```
# # Bitwise Inclusive OR Operator
**Syntax**
bitwise-inc-OR-expression:
bitwise-exc-OR-expression
bitwise-inc-OR-expression | bitwise-exc-OR-expression
*bitwise-exc-OR-expression* is defined in [§§](#bitwise-exclusive-or-operator).
**Constraints**
Each of the operands must have scalar type.
**Semantics**
If either operand does not have type `int`, its value is first converted
to that type.
The result of this operator is the bitwise inclusive-OR of the two
operands, and the type of that result is `int`.
This operator associates left-to-right.
**Examples**
```
0b101111 | 0b101 // 0b101111
$uLetter = 0x41; // letter 'A'
$lLetter = $upCaseLetter | 0x20; // set the 6th bit to make letter 'a'
```
# # Logical AND Operator (form 1)
**Syntax**
logical-AND-expression-1:
bitwise-incl-OR-expression
logical-AND-expression-1 && bitwise-inc-OR-expression
*bitwise-incl-OR-expression* is defined in [§§](#bitwise-inclusive-or-operator).
**Constraints**
Each of the operands must have scalar type.
**Semantics**
If either operand does not have type bool, its value is first converted
to that type.
Given the expression `e1 && e2, e1` is evaluated first. If `e1` is `FALSE`, `e2` is not evaluated, and the result has type `bool`, value `FALSE`. Otherwise, `e2` is evaluated. If `e2` is `FALSE`, the result has type bool, value `FALSE`; otherwise, it has type `bool`, value `TRUE`. There is a sequence point after the evaluation of `e1`.
This operator associates left-to-right.
Except for the difference in precedence, operator `&&` has exactly the
same semantics as operator `and` ([§§](#logical-and-operator-form-2)).
**Examples**
```
if ($month > 1 && $month <= 12) ...
```
# # Logical Inclusive OR Operator (form 1)
**Syntax**
logical-inc-OR-expression-1:
logical-AND-expression-1
logical-inc-OR-expression-1 || logical-AND-expression-1
*logical-exc-OR-expression* is defined in [§§](#bitwise-exclusive-or-operator).
**Constraints**
Each of the operands must have scalar type.
**Semantics**
If either operand does not have type bool, its value is first converted
to that type.
Given the expression `e1 || e2`, `e1` is evaluated first. If `e1` is TRUE, `e2` is not evaluated, and the result has type `bool`, value `TRUE`. Otherwise, `e2` is evaluated. If `e2` is `TRUE`, the result has type `bool`, value `TRUE`; otherwise, it has type `bool`, value `FALSE`. There is a sequence point after the evaluation of `e1`.
This operator associates left-to-right.
**Examples**
```
if ($month < 1 || $month > 12) ...
```
# # Conditional Operator
**Syntax**
conditional-expression:
logical-inc-OR-expression-1
logical-inc-OR-expression-1 ? expressionopt : conditional-expression
*logical-OR-expression* is defined in [§§](#logical-inclusive-or-operator-form-1); and *expression* is
defined in [§§](#general-16).
**Constraints**
The first operand must have scalar type.
**Semantics**
Given the expression `e1 ? e2 : e3`, if `e1` is `TRUE`, then and only then is `e2` evaluated, and the result and its type become the result and type of
the whole expression. Otherwise, then and only then is `e3` evaluated, and
the result and its type become the result and type of the whole
expression. There is a sequence point after the evaluation of `e1`. If `e2`
is omitted, the result and type of the whole expression is the value and
type of `e1` when it was tested.
This operator associates left-to-right.
**Examples**
```
for ($i = -5; $i <= 5; ++$i)
echo "$i is ".(($i & 1 == TRUE) ? "odd\n" : "even\n");
// -----------------------------------------
$a = 10 ? : "Hello"; // result is int with value 10
$a = 0 ? : "Hello"; // result is string with value "Hello"
$i = PHP_INT_MAX;
$a = $i++ ? : "red"; // result is int with value 2147483647 (on a 32-bit
// system) even though $i is now the float 2147483648.0
// -----------------------------------------
$i++ ? f($i) : f(++$i); // the sequence point makes this well-defined
// -----------------------------------------
function factorial($int)
{
return ($int > 1) ? $int * factorial($int - 1) : $int;
}
```
# # Assignment Operators
## # General
**Syntax**
assignment-expression:
conditional-expression
simple-assignment-expression
byref-assignment-expression
compound-assignment-expression
*conditional-expression* is defined in [§§](#conditional-operator);
*simple-assignment-expression* is defined in [§§](#simple-assignment);
*byref-assignment-expression* is defined in [§§](#byref-assignment); and
*compound-assignment-expression* is defined in [§§](#compound-assignment).
**Constraints**
The left-hand operand of an assignment operator must be a modifiable
lvalue.
**Semantics**
These operators associate right-to-left.
## # Simple Assignment
**Syntax**
simple-assignment-expression:
unary-expression = assignment-expression
*unary-expression* is defined in [§§](#general-14); *assignment-expression* is
defined in [§§](#general-15).
**Constraints**
If the location designated by the left-hand operand is a string element,
the key must not be a negative-valued `int`, and the right-hand operand
must have type `string`.
**Semantics**
If *assignment-expression* designates an expression having value type,
see [§§](#value-assignment-of-object-and-resource-types-to-a-local-variable). If *assignment-expression*
designates an expression having handle type, see [§§](#byref-assignment-for-scalar-types-with-local-variables). If
*assignment-expression* designates an expression having array type, see
[§§](#value-assignment-of-array-types-to-local-variables).
The type and value of the result is the type and value of the left-hand
operand after the store (if any [see below]) has taken place. The result
is not an lvalue.
If the location designated by the left-hand operand is a non-existent
array element, a new element is inserted with the designated key and
with a value being that of the right-hand operand.
If the location designated by the left-hand operand is a string element,
then if the key is a negative-valued `int`, there is no side effect.
Otherwise, if the key is a non-negative-valued `int`, the left-most single
character from the right-hand operand is stored at the designated
location; all other characters in the right-hand operand string are
ignored. If the designated location is beyond the end of the
destination string, that string is extended to the new length with
spaces (U+0020) added as padding beyond the old end and before the newly
added character. If the right-hand operand is an empty string, the null
character \\0 (U+0000) is stored.
**Examples**
```
$a = $b = 10 // equivalent to $a = ($b = 10)
$v = array(10, 20, 30);
$v[1] = 1.234; // change the value (and type) of an existing element
$v[-10] = 19; // insert a new element with int key -10
$v["red"] = TRUE; // insert a new element with string key "red"
$s = "red";
$s[1] = "X"; // OK; "e" -> "X"
$s[-5] = "Y"; // warning; string unchanged
$s[5] = "Z"; // extends string with "Z", padding with spaces in [3]-[5]
$s = "red";
$s[0] = "DEF"; // "r" -> "D"; only 1 char changed; "EF" ignored
$s[0] = ""; // "D" -> "\0"
$s["zz"] = "Q"; // warning; defaults to [0], and "Q" is stored there
// -----------------------------------------
class C { ... }
$a = new C; // make $a point to the allocated object
```
## # byRef Assignment
**Syntax**
byref-assignment-expression:
unary-expression = & assignment-expression
*unary-expression* is defined in [§§](#general-14); *assignment-expression* is
defined in [§§](#general-15).
**Constraints**
*unary-expression* must be a variable name.
*assignment-expression* must be an lvalue, a call to a function that
returns a value byRef, or a *new-expression* (see comment below
regarding this).
**Semantics**
*unary-expression* becomes an alias for *assignment-expression*. If
*assignment-expression* designates an expression having value type, see
[§§](#value-assignment-of-object-and-resource-types-to-a-local-variable). If *assignment-expression* designates an expression having
handle type, see [§§](#byref-assignment-of-non-scalar-types-with-local-variables). If *assignment-expression* designates an
expression having array type, see [§§](#deferred-array-copying).
**Examples**
```
$a = 10;
$b = &$a; // make $b an alias of $a
++$a; // increment $a/$b to 11
$b = -12; // sets $a/$b to -12
$a = "abc"; // sets $a/$b to "abc"
unset($b); // removes $b's alias to $a
// -----------------------------------------
function &g2() { $t = "xxx"; return $t; } // return byRef
$b = &g2(); // make $b an alias to "xxx"
```
# # Compound Assignment
**Syntax**
compound-assignment-expression:
unary-expression compound-assignment-operator assignment-expression
compound-assignment-operator: one of
**= *= /= %= += -= .= <<= >>= &= ^= |=
*unary-expression* is defined in [§§](#general-14); *assignment-expression* is
defined in [§§](#general-15).
**Constraints**
Any constraints that apply to the corresponding postfix or binary
operator apply to the compound-assignment form as well.
**Semantics**
The expression `e1 op= e2` is equivalent to `e1 = e1 op (e2)`, except
that `e1` is evaluated once only.
**Examples**
```
$v = 10;
$v += 20; // $v = 30
$v -= 5; // $v = 25
$v .= 123.45 // $v = "25123.45"
$a = [100, 200, 300];
$i = 1;
$a[$i++] += 50; // $a[1] = 250, $i → 2
```
# # Logical AND Operator (form 2)
**Syntax**
logical-AND-expression-2:
assignment-expression
logical-AND-expression-2 and assignment-expression
*assignment-expression* is defined in [§§](#general-15).
**Constraints**
Each of the operands must have scalar type.
**Semantics**
Except for the difference in precedence, operator and has exactly the
same semantics as operator `&&` ([§§](#logical-and-operator-form-1)).
# # Logical Exclusive OR Operator
**Syntax**
logical-exc-OR-expression:
logical-AND-expression-2
logical-exc-OR-expression xor logical-AND-expression-2
*logical-AND-expression* is defined in [§§](#logical-and-operator-form-2).
**Constraints**
Each of the operands must have scalar type.
**Semantics**
If either operand does not have type `bool`, its value is first converted
to that type.
Given the expression `e1 xor e2`, `e1` is evaluated first, then `e2`. If
either `e1` or `e2` is `TRUE`, but not both, the result has type `bool`, value
`TRUE`. Otherwise, the result has type `bool`, value `FALSE`. There is a
sequence point after the evaluation of `e1`.
This operator associates left-to-right.
**Examples**
```
f($i++) XOR g($i) // the sequence point makes this well-defined
```
# # Logical Inclusive OR Operator (form 2)
**Syntax**
logical-inc-OR-expression-2:
logical-exc-OR-expression
logical-inc-OR-expression-2 or logical-exc-OR-expression
*logical-exc-OR-expression* is defined in [§§](#logical-exclusive-or-operator).
**Constraints**
Each of the operands must have scalar type.
**Semantics**
Except for the difference in precedence, operator and has exactly the
same semantics as operator `||` ([§§](#logical-inclusive-or-operator-form-1)).
# # `yield` Operator
**Syntax**
yield-expression:
logical-inc-OR-expression-2
yield array-element-initializer
*logical-inc-OR-expression* is defined in [§§](#logical-inclusive-or-operator-form-2);
*array-element-initializer* is defined in [§§](#array-creation-operator).
**Semantics**
Any function containing a *yield-expression* is a *generator function*.
A generator function generates a collection of zero or more key/value
pairs where each pair represents the next in some series. For example, a
generator might *yield* random numbers or the series of Fibonacci
numbers. When a generator function is called explicitly, it returns an
object of type `Generator` ([§§](#class-generator)), which implements the interface
`Iterator` ([§§](#interface-iterator)). As such, this allows that object to be iterated over
using the `foreach` statement ([§§](#the-foreach-statement)). During each iteration, the Engine
calls the generator function implicitly to get the next key/value pair.
Then the Engine saves the state of the generator for subsequent
key/value pair requests.
This operator produces the result `NULL` unless the method
`Generator->send` ([§§](#class-generator)) was called to provide a result value. This
operator has the side effect of generating the next value in the
collection.
Before being used, an *element-key* must have, or be converted to, type
`int` or `string`. Keys with `float` or `bool` values, or strings whose contents
match exactly the pattern of *decimal-literal* ([§§](#integer-literals)), are
converted to `int` ([§§](#converting-to-integer-type)). Values of all other key types are converted to
`string` ([§§](#converting-to-string-type)).
If *element-key* is omitted from an *array-element-initializer*, an
element key of type `int` is associated with the corresponding
*element-value*. The key associated is one more than the previously
assigned int key for this collection. However, if this is the first
element in this collection with an `int` key, key zero is used. If
*element-key* is provided, it is associated with the corresponding
*element-value*. The resulting key/value pair is made available by
`yield`.
If *array-element-initializer* is omitted, default int-key assignment is
used and each value is `NULL`.
If the generator function definition declares that it returns byRef,
each value in a key/value pair is yielded byRef.
**Examples**
```
function getTextFileLines($filename)
{
$infile = fopen($filename, 'r');
if ($infile == FALSE) { /* deal with the file-open failure */ }
try
{
while ($textLine = fgets($infile)) // while not EOF
{
$textLine = rtrim($textLine, "\r\n"); // strip off terminator
yield $textLine;
}
}
finally
{
fclose($infile);
}
}
foreach (getTextFileLines("Testfile.txt") as $line) { /* process each line */ }
// -----------------------------------------
function series($start, $end, $keyPrefix = "")
{
for ($i = $start; $i <= $end; ++$i)
{
yield $keyPrefix . $i => $i; // generate a key/value pair
}
}
foreach (series(1, 5, "X") as $key => $val) { /* process each key/val pair */ }
```
# # Script Inclusion Operators
## # General
**Syntax**
expression:
yield-expression
include-expression
include-once-expression
require-expression
require-once-expression
*yield-expression* is described in [§§](#yield-operator); *include-expression* is
described in [§§](#the-include-operator); *include-once-expression* is described in
[§§](#the-include_once-operator); *require-expression* is described in [§§](#the-require-operator); and
*require-once-expression* is described in [§§](#the-require_once-operator).
**Semantics:**
When creating large applications or building component libraries, it is
useful to be able to break up the source code into small, manageable
pieces each of which performs some specific task, and which can be
shared somehow, and tested, maintained, and deployed individually. For
example, a programmer might define a series of useful constants and use
them in numerous and possibly unrelated applications. Likewise, a set of
class definitions can be shared among numerous applications needing to
create objects of those types.
An *include file* is a script that is suitable for *inclusion* by
another script. The script doing the including is the *including file*,
while the one being included is the *included file*. A script can be an
including file and an included file, either, or neither.
Using the series-of-constants example, an include file called
`Positions.php` might define the constants `TOP`, `BOTTOM`, `LEFT`, and `RIGHT`,
in their own namespace ([§§](#general-28)), Positions. Using the set-of-classes
example, to support two-dimensional geometry applications, an include
file called `Point.php` might define the class `Point`. An include file
called `Line.php` might define the class Line (where a `Line` is represented
as a pair of Points).An include file, called `Circle.php` might define the
class `Circle` (where a `Circle` is represented as a `Point` for the origin,
and a radius).
If a number of the scripts making up an application each use one or more
of the Position constants, they can each include the corresponding
include file via the `include` operator ([§§](#the-include-operator)). However, most include
files behave the same way each time they are included, so it is
generally a waste of time including the same include file more than once
into the same scope. In the case of the geometry example, any attempt to
include the same include file more than once will result in a fatal
"attempted class type redefinition" error. However, this can be avoided
by using the `include_once` operator ([§§](#the-include_once-operator)) instead.
The `require` operator ([§§](#the-require-operator)) is a variant of the `include` operator,
and the `require_once` operator ([§§](#the-require_once-operator)) is a variant of the
`include_once` operator.
It is important to understand that unlike the C/C++ (or similar)
preprocessor, script inclusion in PHP is not a text substitution
process. That is, the contents of an included file are not treated as if
they directly replaced the inclusion operation source in the including
file.
An inclusion expression can be written to look like a function call;
however, that is not the case, even though an included file can return a
value to its including file.
The name used to specify an include file may contain an absolute or
relative path. In the latter case, an implementation may use the
configuration directive
[`include_path`](http://www.php.net/manual/en/ini.core.php#ini.include-path)
(§xx) to resolve the include file's location.
## # The `include` Operator
**Syntax**
include-expression:
include ( include-filename )
include include-filename
include-filename:
expression
*expression* is defined in [§§](#general-16).
**Constraints:**
*expression* must be a string that designates a file that exists, is
accessible, and whose format is suitable for inclusion (that is, starts
with a PHP start-tag, and optionally ends with a PHP end-tag). However,
if the designated file is not accessible, execution may continue.
**Semantics:**
When an included file is opened, parsing immediately drops out of PHP
mode and into HTML mode at the beginning, and switches back again when
the end of the included file is reached.
Variables defined in an included file take on scope of the source line
on which the inclusion occurs in the including file. However, functions
and classes defined in the included file are given global scope.
If inclusion occurs inside a function definition within the including
file, the complete contents of the included file are treated as though
it were defined inside that function.
Operator `include` has a side effect of including the designated include
file. The result produced by this operator is one of the following:
`FALSE`, which indicates the inclusion attempt failed; the `int` 1, which
indicates the default value for inclusion attempt succeeded; or some
other value, as returned from the included file ([§§](#the-return-statement)).
The library function `get_included_files` (§xx) provides the names of
all files included or required.
**Examples:**
```
$fileName = 'limits' . '.php'; include $fileName;
$inc = include('limits.php');
If ((include 'Positions.php') == 1) ...
```
## # The `include_once` Operator
**Syntax**
include-once-expression:
include_once ( include-filename )
include_once include-filename
*include-filename* is defined in [§§](#the-include-operator).
**Semantics:**
This operator is identical to operator `include` ([§§](#the-include-operator)) except that in
the case of `include_once`, the include file is included once only during
program execution.
Once an include file has been included, a subsequent use of
`include_once` on that include file results in a return value of `TRUE`.
**Examples:**
Point.php:
```
\\ Point.php:
require-expression:
require ( include-filename )
require include-filename
*include-filename* is defined in [§§](#the-include-operator).
**Semantics:**
This operator is identical to operator `include` ([§§](#the-include-operator)) except that in
the case of `require`, failure to find/open the designated include file
terminates program execution.
The library function `get_included_files` (§xx) provides the names of
all files included or required.
## # The `require_once` Operator
**Syntax**
require-once-expression:
require_once ( include-filename )
require_once include-filename
*include-filename* is defined in [§§](#the-include-operator).
**Semantics:**
This operator is identical to operator `require` ([§§](#the-require-operator)) except that in
the case of `require_once`, the include file is included once only during
program execution.
Once an include file has been included, a subsequent use of
`require_once` on that include file results in a return value of TRUE.
# # Constant Expressions
**Syntax**
constant-expression:
array-creation-expression
const-expression
const-expression:
expression
*array-creation-expression* is defined in [§§](#array-creation-operator) and *expression* is
defined in [§§](#general-16).
**Constraints:**
All of the *element-key* and *element-value* *expression*s in
*array-creation-expression* ([§§](#array-creation-operator)) must be literals.
*expression* must have a scalar type, and be a literal or the name of an
existing c-constant ([§§](#general-4)), that is currently in scope.
**Semantics:**
A *const-expression* is the value of a c-constant. A *const-expression*
is required in several contexts, such as in initializer values in a
*const-declaration* ([§§](#constants-2)) and default initial values in a function
definition ([§§](#function-definitions)).
An initializer in a *property-declaration* ([§§](#properties)) is less restrictive
than one in a *const-declaration*.
# Statements
# # General
**Syntax**
statement:
compound-statement
labeled-statement
expression-statement
selection-statement
iteration-statement
jump-statement
declare-statement
const-declaration
function-definition
class-declaration
interface-declaration
trait-declaration
namespace-definition
namespace-use-declaration
global-declaration
function-static-declaration
*compound-statement* is defined in [§§](#compound-statements); *labeled-statement* is defined
in [§§](#labeled-statements); *expression-statement* is defined in [§§](#expression-statements);
*selection-statement* is defined in [§§](#general-18); *iteration-statement* is
defined in [§§](#general-19); *jump-statement* is defined in [§§](#general-20);
*declare-statement* is defined in [§§](#the-declare-statement); *const-declaration* is defined
in [§§](#constants-2); *function-definition* is defined in [§§](#function-definitions); *class-declaration*
is defined in [§§](#class-declarations); *interface-declaration* is defined in [§§](#interface-declarations);
*trait-declaration* is defined in [§§](#trait-declarations); *namespace-definition* is
defined in [§§](#defining-namespaces); *namespace-use-declaration* is defined in [§§](#namespace-use-declarations);
*global-declaration* is defined in [§§](#global-variables); and
*function-static-declaration* is defined in [§§](#function-statics).
# # Compound Statements
**Syntax**
compound-statement:
{ statement-listopt }
statement-list:
statement
statement-list statement
*statement* is defined in [§§](#general-17).
**Semantics**
A *compound statement* allows a group of zero of more statements to be
treated syntactically as a single statement. A compound statement is
often referred to as a *block*.
**Examples**
```
if (condition)
{ // braces are needed as the true path has more than one statement
// statement-1
// statement-2
}
else
{ // braces are optional as the false path has only one statement
// statement-3
}
// -----------------------------------------
while (condition)
{ // the empty block is equivalent to a null statement
}
```
# # Labeled Statements
**Syntax**
labeled-statement:
named-label
case-label
default-label
named-label:
name : statement
case-label:
case expression case-default-label-terminator statement
default-label:
default case-default-label-terminator statement
case-default-label-terminator:
:
;
*name* is defined in [§§](#names); *statement* is defined in [§§](#general-17); and
*expression* is defined in [§§](#general-16).
**Constraints**
A named label must only be used as the target of a `goto` statement
([§§](#the-goto-statement)).
Named labels must be unique within a function.
A case and default label must only occur inside a `switch` statement
([§§](#the-switch-statement)).
**Semantics**
Any statement may be preceded by a token sequence that declares a name
as a label name. The presence of a label does not alter the flow of
execution.
# # Expression Statements
**Syntax**
expression-statement:
expressionopt ;
*expression* is defined in [§§](#general-16).
**Semantics**
If present, *expression* is evaluated for its side effects, if any, and
any resulting value is discarded. If *expression* is omitted, the
statement is a *null statement*, which has no effect on execution.
**Examples**
```
$i = 10; // $i is assigned the value 10; result (10) is discarded
++$i; // $i is incremented; result (11) is discarded
$i++; // $i is incremented; result (11) is discarded
DoIt(); // function DoIt is called; result (return value) is discarded
// -----------------------------------------
$i; // no side effects, result is discarded. Vacuous but permitted
123; // likewise for this one and the two statements following
34.5 * 12.6 + 11.987;
TRUE;
// -----------------------------------------
function findValue($table, $value) // where $table is 2x3 array
{
for ($row = 0; $row <= 1; ++$row)
{
for ($colm = 0; $colm <= 2; ++$colm)
{
if ($table[$row][$colm] == $value)
{
// ...
goto done;
}
}
}
// ...
done:
; // null statement needed as a label must precede a statement
}
```
# # Selection Statements
## # General
**Syntax**
selection-statement:
if-statement
switch-statement
*if-statement* is defined in [§§](#the-if-statement) and *switch-statement* is defined
in [§§](#the-switch-statement).
**Semantics**
Based on the value of a controlling expression, a selection statement
selects among a set of statements.
## # The `if` Statement
**Syntax**
if-statement:
if ( expression ) statement elseif-clauses-1opt else-clause-1opt
if ( expression ) : statement-list elseif-clauses-2opt else-clause-2opt endif ;
elseif-clauses-1:
elseif-clause-1
elseif-clauses-1 elseif-clause-1
elseif-clause-1:
elseif ( expression ) statement
else-clause-1:
else statement
elseif-clauses-2:
elseif-clause-2
elseif-clauses-2 elseif-clause-2
elseif-clause-2:
elseif ( expression ) : statement-list
else-clause-2:
else : statement-list
*expression* is defined in [§§](#general-16); *statement* is defined in [§§](#general-17);
and *statement-list* is defined in [§§](#compound-statements).
**Constraints**
The controlling expression *expression* must have type `bool` or be
implicitly convertible to that type.
**Semantics**
The two forms of the `if` statement are equivalent; they simply provide
alternate styles.
If *expression* tests `TRUE`, the *statement* that follows immediately is
executed. Otherwise, if an `elseif` clause is present the *statement*
immediately following the `elseif` is executed. Otherwise, any other
`elseif` *expression*s are evaluated. If none of those tests `TRUE`, if an
`else` clause is present the *statement* immediately following the `else` is
executed.
An `else` clause is associated with the lexically nearest preceding `if` or
`elseif` that is permitted by the syntax.
**Examples**
```
if ($count > 0)
{
...
...
...
}
// -----------------------------------------
goto label1;
echo "Unreachable code\n";
if ($a)
{
label1:
...
}
else
{
...
}
// -----------------------------------------
if (1)
...
if (0)
...
else // this else does NOT go with the outer if
...
if (1)
{
...
if (0)
...
}
else // this else does go with the outer if
...
```
## # The `switch` Statement
**Syntax**
switch-statement:
switch ( expression ) compound-statement
switch ( expression ) : statement-list endswitch;
*expression* is defined in [§§](#general-16); and *compound-statement* and
*statement-list* are defined in [§§](#compound-statements).
**Constraints**
The controlling expression *expression* must have scalar type.
The *statement-list* must not contain any *compound-statement*s.
There must be at most one default label.
**Semantics**
The two forms of the `switch` statement are equivalent; they simply
provide alternate styles.
Based on the value of its *expression*, a `switch` statement transfers
control to a case label (§[[11.3](#labeled-statements)](#labeled-statements)); to a default label (§[[11.3](#labeled-statements)](#labeled-statements)), if one
exists; or to the statement immediately following the end of the `switch`
statement. A case or default label is only reachable directly within its
closest enclosing `switch` statement.
On entry to the `switch` statement, the controlling expression is
evaluated and then compared with the value of the case-label-expression
values, in lexical order. If one matches, control transfers to the
statement following the corresponding case label. If there is no match,
then if there is a default label, control transfers to the statement
following that; otherwise, control transfers to the statement
immediately following the end of the `switch` statement. If a `switch`
contains more than one case label whose values compare equal to the
controlling expression, the first in lexical order is consider the
match.
An arbitrary number of statements can be associated with any case or
default label. In the absence of a `break` statement ([§§](#the-break-statement)) at the end
of a set of such statements, control drops through into any following
case or default label. Thus, if all cases and the default end in break
and there are no duplicate-valued case labels, the order of case and
default labels is insignificant.
Case-label values can be runtime expressions, and the types of sibling
case-label values need not be the same.
Switches may nested, in which case, each `switch` has its own set of
`switch` clauses.
**Examples**
```
$v = 10;
switch ($v)
{
default:
echo "default case: \$v is $v\n";
break; // break ends "group" of default statements
case 20:
echo "case 20\n";
break; // break ends "group" of case 20 statements
case 10:
echo "case 10\n"; // no break, so control drops into next label's "group"
case 30:
echo "case 30\n"; // no break, but then none is really needed either
}
// -----------------------------------------
$v = 30;
switch ($v)
{
case 30.0: // <===== this case matches with 30
echo "case 30.0\n";
break;
default:
echo "default case: \$v is $v\n";
break;
case 30: // <===== rather than this case matching with 30
echo "case 30\n";
break;
}
// -----------------------------------------
switch ($v)
{
case 10 + $b: // non-constant expression
// ...
case $v < $a: // non-constant expression
// ...
// ...
}
```
# # Iteration Statements
## # General
**Syntax**
iteration-statement:
while-statement
do-statement
for-statement
foreach-statement
*while-statement* is defined in [§§](#the-while-statement); *do-statement* is defined in
[§§](#the-do-statement); *for-statement* is defined in [§§](#the-for-statement); and *foreach-statement*
is defined in [§§](#the-foreach-statement).
# # The `while` Statement
**Syntax**
while-statement:
while ( expression ) statement
while ( expression ) : statement-list endwhile ;
*expresion* is defined in [§§](#general-16); *statement* is defined in [§§](#general-17); and
*statement-list* is defined in [§§](#compound-statements).
**Constraints**
The controlling expression *expression* must have type `bool` or be
implicitly convertible to that type.
**Semantics**
The two forms of the `while` statement are equivalent; they simply provide
alternate styles.
If *expression* tests `TRUE`, the *statement* that follows immediately is
executed, and the process is repeated. If *expression* tests `FALSE`,
control transfers to the point immediately following the end of the
`while` statement. The loop body, *statement*, is executed zero or more
times.
**Examples**
```
$i = 1;
while ($i <= 10):
echo "$i\t".($i * $i)."\n"; // output a table of squares
++$i;
endwhile;
// -----------------------------------------
while (TRUE)
{
// ...
if ($done)
break; // break out of the while loop
// ...
}
```
# # The `do` Statement
**Syntax**
do-statement:
do statement while ( expression ) ;
*statement* is defined in [§§](#general-17) and *expresion* is defined in [§§](#general-16).
(Note: There is no `:/enddo` alternate syntax.)
**Constraints**
The controlling expression *expression* must have type `bool` or be
implicitly convertible to that type.
**Semantics**
First, *statement* is executed and then *expression* is tested. If its
value is `TRUE`, the process is repeated. If *expression* tests `FALSE`,
control transfers to the point immediately following the end of the `do`
statement. The loop body, *statement*, is executed one or more times.
**Examples**
```
$i = 1;
do
{
echo "$i\t".($i * $i)."\n"; // output a table of squares
++$i;
}
while ($i <= 10);
```
# # The `for` Statement
**Syntax**
for-statement:
for ( for-initializeropt ; for-controlopt ; for-end-of-loopopt ) statement
for ( for-initializeropt ; for-controlopt ; for-end-of-loopopt ) : statement-list endfor ;
for-initializer:
for-expression-group
for-control:
for-expression-group
for-end-of-loop:
for-expression-group
for-expression-group:
expression
for-expression-group , expression
*statement* is defined in [§§](#general-17); *statement-list* is defined in [§§](#compound-statements);
and *expression* is defined in [§§](#general-16).
Note: Unlike C/C++, PHP does not support a comma operator, per se.
However, the syntax for the `for` statement has been extended from that of
C/C++ to achieve the same results in this context.
**Constraints**
The controlling expression—the right-most *expression* in
*for-control*—must have type `bool` or be implicitly convertible to that
type.
**Semantics**
The two forms of the `for` statement are equivalent; they simply provide
alternate styles.
The group of expressions in *for-initializer* is evaluated once,
left-to-right, for their side effects. Then the group of expressions in
*for-control* is evaluated left-to-right (with all but the right-most
one for their side effects only), with the right-most expression's value
being tested. If that tests `TRUE`, *statement* is executed, and the group
of expressions in *for-end-of-loop* is evaluated left-to-right, for
their side effects only. Then the process is repeated starting with
*for-control*. If the right-most expression in *for-control* tests
`FALSE`, control transfers to the point immediately following the end of
the `for` statement. The loop body, *statement*, is executed zero or more
times.
If *for-initializer* is omitted, no action is taken at the start of the
loop processing. If *for-control* is omitted, this is treated as if
*for-control* was an expression with the value `TRUE`. If
*for-end-of-loop* is omitted, no action is taken at the end of each
iteration.
**Examples**
```
for ($i = 1; $i <= 10; ++$i)
{
echo "$i\t".($i * $i)."\n"; // output a table of squares
}
// -----------------------------------------
// omit 1st and 3rd expressions
$i = 1;
for (; $i <= 10;):
echo "$i\t".($i * $i)."\n"; // output a table of squares
++$i;
endfor;
// -----------------------------------------
// omit all 3 expressions
$i = 1;
for (;;)
{
if ($i > 10)
break;
echo "$i\t".($i * $i)."\n"; // output a table of squares
++$i;
}
// -----------------------------------------
// use groups of expressions
for ($a = 100, $i = 1; ++$i, $i <= 10; ++$i, $a -= 10)
{
echo "$i\t$a\n";
}
```
# # The `foreach` Statement
**Syntax**
foreach-statement:
foreach ( foreach-collection-name as foreach-keyopt foreach-value ) statement
foreach ( foreach-collection-name as foreach-keyopt foreach-value ) : statement-list endforeach ;
foreach-collection-name:
expression
foreach-key:
expression =>
foreach-value:
&opt expression
list-intrinsic
*statement* is defined in [§§](#general-17); *statement-list* is defined in [§§](#compound-statements);
*variable-name* is defined in [§§](#names); *list-intrinsic* is defined in
[§§](#list); and *expression* is defined in [§§](#general-16).
**Constraints**
The variable designated by *foreach-collection-name* must be a
collection.
Each *expression* must designate a variable name.
**Semantics**
The two forms of the `foreach` statement are equivalent; they simply
provide alternate styles.
The *foreach* statement iterates over the set of elements in the
collection designated by *foreach-collection-name*, starting at the
beginning, executing *statement* each iteration. On each iteration, if
the `&` is present in *foreach-value*, the variable designated by the
corresponding *expression* is made an alias to the current element. If
the `&` is omitted, the value of the current element is assigned to the
corresponding variable. The loop body, *statement*, is executed zero or
more times. After the loop terminates, *expression* in *foreach-value*
has the same meaning it had after the final iteration, if any.
If *foreach-key* is present, the variable designated by its *expression*
is assigned the current element's key value.
In the *list-intrinsic* case, a value that is an array is split into
individual elements.
**Examples**
```
$colors = array("red", "white", "blue");
foreach ($colors as $color):
// ...
endforeach;
// -----------------------------------------
foreach ($colors as $key => $color)
{
// ...
}
// -----------------------------------------
// Modify the local copy of an element's value
foreach ($colors as $color)
{
$color = "black";
}
// -----------------------------------------
// Modify the the actual element itself
foreach ($colors as &$color) // note the &
{
$color = "black";
}
```
# # Jump Statements
## # General
**Syntax**
jump-statement:
goto-statement
continue-statement
break-statement
return-statement
throw-statement
*goto-statement* is defined in [§§](#the-goto-statement); *continue-statement* is defined
in [§§](#the-continue-statement); *break-statement* is defined in [§§](#the-break-statement); *return-statement*
is defined in [§§](#the-return-statement); and *throw-statement* is defined in [§§](#the-throw-statement).
## # The `goto` Statement
**Syntax**
goto-statement:
goto name ;
*name* is defined in [§§](#names).
**Constraints**
The name in a `goto` statement must be that of a named label located
somewhere in the current script. Control must not be transferred into or
out of a function, or into an iteration statement ([§§](#iteration-statements)) or a `switch`
statement ([§§](#the-switch-statement)).
A `goto` statement must not attempt to transfer control out of a
finally-block ([§§](#the-try-statement)).
**Semantics**
A `goto` statement transfers control unconditionally to the named label
([§§](#labeled-statements)).
A `goto` statement may break out of a construct that is fully contained
within a finally-block.
**Examples**
```
function findValue($table, $v) // where $table is 2x3 array
{
for ($row = 0; $row <= 1; ++$row)
{
for ($colm = 0; $colm <= 2; ++$colm)
{
if ($table[$row][$colm] == $v)
{
echo "$v was found at row $row, column $colm\n";
goto done; // not quite the same as break 2!
}
}
}
echo "$v was not found\n";
done:
; // note that a label must always precede a statement
}
```
## # The `continue` Statement
**Syntax**
continue-statement:
continue breakout-levelopt ;
breakout-level:
integer-literal
*integer-literal* is defined in [§§](#integer-literals).
**Constraints**
The breakout level must not be zero, and it must not exceed the level of
actual enclosing iteration and/or `switch` statements.
A `continue` statement must not attempt to break out of a finally-block
([§§](#the-try-statement)).
**Semantics**
A `continue` statement terminates the execution of the innermost enclosing
iteration ([§§](#iteration-statements)) or `switch` ([§§](#the-switch-statement)) statement.
A `continue` statement terminates the execution of one or more enclosing
iteration ([§§](#iteration-statements)) or `switch` ([§§](#the-switch-statement)) statements. If *breakout-level* is
greater than one, the next iteration (if any) of the next innermost
enclosing iteration or switch statement is started; however, if that
statement is a `for` statement and it has a *for-end-of-loop*, its
expression group for the current iteration is evaluated first. If
*breakout-level* is 1, the behavior is the same as for `break 1`. If
*breakout-level* is omitted, a level of 1 is assumed.
A `continue` statement may break out of a construct that is fully
contained within a finally-block.
**Examples**
```
for ($i = 1; $i <= 5; ++$i)
{
if (($i % 2) == 0)
continue;
echo "$i is odd\n";
}
```
# # The `break` Statement
**Syntax**
break-statement:
break breakout-levelopt ;
*breakout-level* is defined in [§§](#the-continue-statement).
**Constraints**
The breakout level must not be zero, and it must not exceed the level of
actual enclosing iteration and/or `switch` statements.
A `break` statement must not attempt to break out of a finally-block
([§§](#the-try-statement)).
**Semantics**
A `break` statement terminates the execution of one or more enclosing
iteration ([§§](#iteration-statements)) or `switch` ([§§](#the-switch-statement)) statements. The number of levels
broken out is specified by *breakout-level*. If *breakout-level* is
omitted, a level of 1 is assumed.
A `break` statement may break out of a construct that is fully contained
within a finally-block.
**Examples**
```
$i = 1;
for (;;)
{
if ($i > 10)
break;
// ...
++$i;
}
// -----------------------------------------
for ($row = 0; $row <= 1; ++$row)
{
for ($colm = 0; $colm <= 2; ++$colm)
{
if (some-condition-set)
{
break 2;
}
// ...
}
}
// -----------------------------------------
for ($i = 10; $i <= 40; $i +=10)
{
switch($i)
{
case 10: /* ... */; break; // breaks to the end of the switch
case 20: /* ... */; break 2; // breaks to the end of the for
case 30: /* ... */; break; // breaks to the end of the switch
}
}
```
## # The `return` Statement
**Syntax**
return-statement:
return expressionopt ;
*expression* is defined in [§§](#general-16).
**Constraints**
The *expression* in a *return-statement* in a generator function
([§§](#yield-operator)) must be the literal `NULL` or be omitted.
**Semantics**
A `return` statement from within a function terminates the execution of
that function normally, and depending on how the function was defined
([§§](#function-calls)), it returns the value of *expression* to the function's caller
by value or byRef. If *expression* is omitted the value `NULL` is used.
If execution flows into the closing brace (`}`) of a function, `return
NULL;` is implied.
A function may have any number of `return` statements, whose returned
values may have different types.
If an undefined variable is returned byRef, that variable becomes
defined, with a value of `NULL`.
A `return` statement is permitted in a try-block ([§§](#the-try-statement)) and a catch-block
([§§](#the-try-statement)). However, it is unspecified whether a `return` statement is
permitted in a finally-block ([§§](#the-try-statement)), and, if so, the semantics of
that.
Using a `return` statement inside a finally-block will override any other
`return` statement or thrown exception from the try-block and all its
catch-blocks. Code execution in the parent stack will continue as if
the exception was never thrown.
If an uncaught exception exists when a finally-block is executed, if
that finally-block executes a `return` statement, the uncaught exception
is discarded.
In an included file ([§§](#general-16)) a `return` statement may occur outside any
function. This statement terminates processing of that script and
returns control to the including file. If *expression* is present, that
is the value returned; otherwise, the value `NULL` is returned. If
execution flows to the end of the script, `return 1;` is implied. However,
if execution flows to the end of the top level of a script, `return 0;` is
implied. Likewise, if *expression* is omitted at the top level. (See
exit ([§§](#exitdie)).)
Returning from a constructor or destructor behaves just like returning
from a function.
A `return` statement inside a generator function causes the generator to
terminate.
Return statements can also be used in the body of anonymous functions.
`return` terminates the execution of source code given to the intrinsic
[`eval` ([§§](#eval))](http://www.php.net/manual/en/function.eval.php).
**Examples**
```
function f() { return 100; } // f explicitly returns a value
function g() { return; } // g explicitly returns an implicit NULL
function h() { } // h implicitly returns NULL
// -----------------------------------------
// j returns one of three dissimilarly-typed values
function j($x)
{
if ($x > 0)
{
return "Positive";
}
else if ($x < 0)
{
return -1;
}
// for zero, implied return NULL
}
function &compute() { ...; return $value; } // returns $value byRef
// -----------------------------------------
class Point
{
private static $pointCount = 0;
public static function getPointCount()
{
return self::$pointCount;
}
...
}
```
**Implementation Notes**
Although *expression* is a full expression ([§§](#general-10)), and there is a
sequence point ([§§](#general-10)) at the end of that expression, as stated in
[§§](#general-10), a side effect need not be executed if it can be determined that
no other program code relies on its having happened. (For example, in
the cases of `return $a++;` and `return ++$a;`, it is obvious what value
must be returned in each case, but if `$a` is a variable local to the
enclosing function, `$a` need not actually be incremented.
## # The `throw` Statement
**Syntax**
throw-statement:
throw expression ;
*expression* is defined in [§§](#general-16).
**Constraints**
The type of *expression* must be Exception ([§§](#class-exception)) or a subclass of that
class.
*expression* must be such that an alias to it can be created.
**Semantics**
A `throw` statement throws an exception immediately and unconditionally.
Control never reaches the statement immediately following the throw. See
[§§](#general-27) and [§§](#the-try-statement) for more details of throwing and catching exceptions,
and how uncaught exceptions are dealt with.
Rather than handle an exception, a catch-block may (re-)throw the same
exception that it caught, or it can throw an exception of a different
type.
**Examples**
```
throw new Exception;
throw new Exception("Some message", 123);
class MyException extends Exception { ... }
throw new MyException;
```
# # The `try` Statement
**Syntax**
try-statement:
try compound-statement catch-clauses
try compound-statement finally-clause
try compound-statement catch-clauses finally-clause
catch-clauses:
catch-clause
catch-clauses catch-clause
catch-clause:
catch ( parameter-declaration-list ) compound-statement
finally-clause:
finally compound-statement
*compound-statement* is defined in [§§](#compound-statements) and
*parameter-declaration-list* is defined in [§§](#function-definitions).
**Constraints**
In a *catch-clause*, *parameter-declaration-list* must contain only one
parameter, and its type must be `Exception` ([§§](#class-exception)) or a type derived from
that class, and that parameter must not be passed byRef.
**Semantics**
In a *catch-clause*, *identifier* designates an *exception variable*
passed in by value. This variable corresponds to a local variable with a
scope that extends over the catch-block. During execution of the
catch-block, the exception variable represents the exception currently
being handled.
Once an exception is thrown, the Engine searches for the nearest
catch-block that can handle the exception. The process begins at the
current function level with a search for a try-block that lexically
encloses the throw point. All catch-blocks associated with that
try-block are considered in lexical order. If no catch-block is found
that can handle the run-time type of the exception, the function that
called the current function is searched for a lexically enclosing
try-block that encloses the call to the current function. This process
continues until a catch-block is found that can handle the current
exception.
If a matching catch-block is located, the Engine prepares to transfer
control to the first statement of that catch-block. However, before
execution of that catch-block can start, the Engine first executes, in
order, any finally-blocks associated with try-blocks nested more deeply
than the one that caught the exception.
If no matching catch-block is found, the behavior is
implementation-defined.
**Examples**
```
function getTextLines($filename)
{
$infile = fopen($filename, 'r');
if ($infile == FALSE) { /* deal with an file-open failure */ }
try
{
while ($textLine = fgets($infile)) // while not EOF
{
yield $textLine; // leave line terminator attached
}
}
finally
{
fclose($infile);
}
}
// -----------------------------------------
class DeviceException extends Exception { ... }
class DiskException extends DeviceException { ... }
class RemovableDiskException extends DiskException { ... }
class FloppyDiskException extends RemovableDiskException { ... }
try
{
process(); // call a function that might generate a disk-related exception
}
catch (FloppyDiskException $fde) { ... }
catch (RemovableDiskException $rde) { ... }
catch (DiskException $de) { ... }
catch (DeviceException $dve) { ... }
finally { ... }
```
# # The `declare` Statement
**Syntax**
declare-statement:
declare ( declare-directive ) statement
declare ( declare-directive ) : statement-list enddeclare ;
declare ( declare-directive ) ;
declare-directive:
ticks = declare-tick-count
encoding = declare-character-encoding
declare-tick-count
expression
declare-character-encoding:
expression
*statement* is defined in [§§](#general-17); *statement-list* is defined in [§§](#compound-statements);
and *expression* is defined in [§§](#the-include-operator).
**Constraints**
*tick-count* must designate a value that is, or can be converted, to an
integer having a non-negative value.
*character-encoding* must designate a string whose value names an
8-bit-[character
encoding](http://en.wikipedia.org/wiki/Character_encoding).
Except for white space, a *declare-statement* in a script that specifies
*character-encoding* must be the first thing in that script.
**Semantics**
The first two forms of the `declare` statement are equivalent; they simply
provide alternate styles.
The `declare` statement sets an *execution directive* for its *statement*
body, or for the `;`-form, for the remainder of the script or until the
statement is overridden by another *declare-statement*, whichever comes
first. As the parser is executing, certain statements are considered
*tickable*. For every *tick-count* ticks, an event occurs, which can be
serviced by the function previously registered by the library function
[`register_tick_function`
(§xx)](http://www.php.net/manual/en/function.register-tick-function.php).
Tick event monitoring can be disabled by calling the library function
[`unregister_tick_function`
(§xx)](http://www.php.net/manual/en/function.unregister-tick-function.php).
This facility allows a profiling mechanism to be developed.
Character encoding can be specified on a script-by-script basis using
the encoding directive. The joint ISO and IEC standard ISO/IEC
8859 standard series (
function-definition:
function-definition-header compound-statement
function-definition-header:
function &opt name ( parameter-declaration-listopt )
parameter-declaration-list:
parameter-declaration
parameter-declaration-list , parameter-declaration
parameter-declaration:
type-hintopt &opt variable-name default-argument-specifieropt
type-hint:
array
callable
qualified-name
default-argument-specifier:
= const-expression
*const-expression* is defined in [§§](#constant-expressions). *qualified-name* is defined in
[§§](#names).
**Constraints**
Each parameter name in a *function-definition* must be distinct.
A conditionally defined function ([§§](#general-22)) must exist before any calls are
made to that function.
*parameter-declaration* must not contain `&` if *type-hint* is `array` or
`callable`.
**Semantics**
A *function-definition* defines a function called *name*. Function names
are **not** case-sensitive. A function can be defined with zero or more
parameters, each of which is specified in its own
*parameter-declaration* in a *parameter-declaration-list*. Each
parameter has a name, *variable-name*, and optionally, a
*default-argument-specifier*. An `&` in *parameter-declaration* indicates
that parameter is passed byRef ([§§](#assignment)) rather than by value. An `&`
before *name* indicates that the value returned from this function is to
be returned byRef. Function-value returning is described in [§§](#the-return-statement).
When the function is called, if there exists a parameter for which there
is a corresponding argument, the argument is assigned to the parameter
variable using value assignment, while for passing-byRef, the argument is
assigned to the parameter variable using byRef assignment ([§§](#assignment), [§§](#argument-passing)). If that parameter has no corresponding argument, but the parameter has a
default argument value, for passing-by-value or passing-byRef, the default
value is assigned to the parameter variable using value assignment.
Otherwise, if the parameter has no corresponding argument and the parameter
does not have a default value, the parameter variable is non-existent and no corresponding VSlot ([§§](#the-memory-model)) exists. After all possible parameters have been
assigned initial values or aliased to arguments, the body of the function,
*compound-statement*, is executed. This execution may terminate normally
(§[[4.3](#program-termination)](#program-termination), [§§](#the-return-statement)) or abnormally (§[[4.3](#program-termination)](#program-termination)).
Each parameter is a variable local to the parent function, and is a
modifiable lvalue.
A *function-definition* may exist at the top level of a script, inside
any *compound-statement*, in which case, the function is conditionally
defined ([§§](#general-22)), or inside a *method-declaration* ([§§](#methods)).
By default, a parameter will accept an argument of any type. However, by
specifying a *type-hint*, the types of argument accepted can be
restricted. By specifying `array`, only an argument designating an array
type is accepted. By specifying `callable`, only an argument designating a
function is accepted. By specifying *qualified-name*, only an instance
of a class having that type, or being derived from that type, are
accepted, or only an instance of a class that implements that interface
type directly or indirectly is accepted.
# # Variable Functions
If a variable name is followed by the function-call operator `()`
([§§](#function-call-operator)), and the value of that variable is a string containing the
name of a function currently defined and visible, that function will be
executed.
The library function `is_callable` (§xx) reports whether the contents of
a variable can be called as a function.
# # Anonymous Functions
An *anonymous function*, also known as a *closure*, is a function
defined with no name. As such, it must be defined in the context of an
expression whose value is used immediately to call that function, or
that is saved in a variable for later execution. An anonymous function
is defined via the anonymous function-creation operator ([§§](#anonymous-function-creation)).
For both `__FUNCTION__` and `__METHOD__` ([§§](#context-dependent-constants)), an anonymous
function's name is `{closure}`. All anonymous functions created in the
same scope have the same name.
# Classes
# # General
A class is a type that may contain zero or more explicitly declared
*members*, which can be any combination of *class constants* ([§§](#constants-2));
data members, called *properties* ([§§](#properties)); and function members, called
*methods* ([§§](#methods)). (The ability to add properties and methods to an
instance at runtime is described in [§§](#dynamic-members).) An object (often called an
*instance*) of a class type is created (i.e., *instantiated*) via the
new operator ([§§](#the-new-operator)).
PHP supports inheritance ([§§](#class-declarations)), a means by which a *derived class* can
*extend* and specialize a single *base class*. However, unlike numerous
other languages, classes in PHP are **not** all derived from a common
ancestor. An *abstract* class ([§§](#class-declarations)) is a base type intended for
derivation, but which cannot be instantiated directly. A *concrete*
class is a class that is not abstract. A *final* class ([§§](#class-declarations)) is one
from which other classes cannot be derived.
A class may *implement* one or more *interfaces* ([§§](#class-declarations), [§§](#general-25)), each of
which defines a contract.
A class can *use* one or more traits ([§§](#general-26)), which allows a class to
have some of the benefits of multiple inheritance.
A *constructor* ([§§](#constructors)) is a special method that is used to initialize
an instance immediately after it has been created. A *destructor*
([§§](#destructors)) is a special method that is used to free resources when an
instance is no longer needed. Other special methods exist; they are
described in ([§§](#methods-with-special-semantics)).
The members of a class each have a default or explicitly declared
*visibility*, which determines what source code can access them. A
member with `private` visibility may be accessed only from within its own
class. A member with `protected` visibility may be accessed only from
within its own class and from classes derived from that class. Access to
a member with `public` visibility is unrestricted.
The *signature* of a method is a combination of the parent class name,
that method's name, and its parameter list, including type hints and
indication for arguments passed using byRef, and whether the resulting
value is returned byRef.
Methods and properties from a base class can be *overridden* in a
derived class by redeclaring them with the same signature defined in the
base class.
When an instance is allocated, new returns a handle that points to that
object. As such, assignment of a handle does not copy the object itself.
(See [§§](#cloning-objects) for a discussion of shallow and deep copying.)
# # Class Declarations
**Syntax**
class-declaration:
class-modifieropt class name class-base clauseopt class-interface-clauseopt { trait-use-clausesopt class-member-declarationsopt }
class-modifier:
abstract
final
class-base-clause:
extends qualified-name
class-interface-clause:
implements qualified-name
class-interface-clause , qualified-name
*qualified-name* is defined in [§§](#names). *class-member-declarations* is
defined in [§§](#class-members). *trait-use-clauses* ~~ is defined in [§§](#trait-declarations)
**Constraints**
A class must not be derived directly or indirectly from itself.
A *class-declaration* containing any *class-member-declarations* that
have the modifier `abstract` must itself have an `abstract`
*class-modifier*.
*class-base-clause* must not name a final class.
*qualified-name* in *class-base-clause* must name a class type, and must
not be `parent`, `self`, or `static`.
A concrete class must implement each of the methods from all the
interfaces ([§§](#general-25)) specified in *class-interface-clause*, using the
exact same signature as defined in each interface.
*qualified-name* in *class-interface-clause* must name an interface
type.
**Semantics**
A *class-declaration* defines a class type by the name *name*. Class
names are case-insensitive.
The `abstract` modifier declares a class usable only as a base class; the
class cannot be instantiated directly. An abstract class may contain one
or more abstract members, but it is not required to do so. When a
concrete class is derived from an abstract class, the concrete class
must include an implementation for each of the abstract members it
inherits.
The `final` modifier prevents a class from being used as a base class.
The optional *class-base-clause* specifies the one base class from which
the class being defined is derived. In such a case, the derived class
inherits all the members from the base class.
The optional *class-interface-clause* specifies the one or more
interfaces that are implemented by the class being defined.
A class can use one or more traits via a *trait-use-clauses*; see [§§](#general-26)
and [§§](#trait-declarations).
**Examples**
```
abstract class Vehicle
{
public abstract function getMaxSpeed();
...
}
abstract class Aircraft extends Vehicle
{
public abstract function getMaxAltitude();
...
}
class PassengerJet extends Aircraft
{
public function getMaxSpeed()
{
// implement method
}
public function getMaxAltitude()
{
// implement method
}
...
}
$pj = new PassengerJet(...);
echo "\$pj's maximum speed: " . $pj->getMaxSpeed() . "\n";
echo "\$pj's maximum altitude: " . $pj->getMaxAltitude() . "\n";
// -----------------------------------------
final class MathLibrary
{
private function MathLibrary() {} // disallows instantiation
public static function sin() { ... }
// ...
}
$v = MathLibrary::sin(2.34);
// -----------------------------------------
interface MyCollection
{
function put($item);
function get();
}
class MyList implements MyCollection
{
public function put($item)
{
// implement method
}
public function get()
{
// implement method
}
...
}
```
# # Class Members
**Syntax**
class-member-declarations:
class-member-declaration
class-member-declarations class-member-declaration
class-member-declaration:
const-declaration
property-declaration
method-declaration
constructor-declaration
destructor-declaration
*const-declaration* is defined in [§§](#constants-2); *property-declaration* is
defined in [§§](#properties); *method-declaration* is defined in [§§](#methods);
*constructor-declaration* is defined in [§§](#names); and
*destructor-declaration* is defined in [§§](#destructors).
**Semantics**
The members of a class are those specified by its
*class-member-declaration*s, and the members inherited from its base
class. (A class may also contain dynamic members, as described in [§§](#dynamic-members).
However, as these have no compile-time names, they can only be accessed
via method calls.)
A class may contain the following members:
- Constants – the constant values associated with the class ([§§](#constants-2)).
- Properties – the variables of the class ([§§](#properties)).
- Methods – the computations and actions that can be performed by the
class ([§§](#methods), [§§](#methods-with-special-semantics)).
- Constructor – the actions required to initialize an instance of the
class ([§§](#constructors))
- Destructor – the actions to be performed when an instance of the
class is no longer needed ([§§](#destructors)).
A number of names are reserved for methods with special semantics, which
user-defined versions must follow. These are described in ([§§](#methods-with-special-semantics)).
Methods and properties can either be *static* or *instance* members. A
static member is declared using `static`. An instance member is one that
is not static. The name of a static method or property can never be used
on its own; it must always be used as the right-hand operand of the
scope resolution operator ([§§](#scope-resolution-operator)). The name of an instance method or
property can never be used on its own; it must always be used as the
right-hand operand of the member selection operator ([§§](#member-selection-operator)).
Each instance of a class contains its own, unique set of instance
properties of that class. An instance member is accessed via the
`->` operator ([§§](#member-selection-operator)). In contrast, a static property designates
exactly one VSlot for its class, which does not belong to any instance,
per se. A static property exists whether or not any instances of that
class exist. A static member is accessed via the `::` operator ([§§](#scope-resolution-operator)).
When any instance method operates on a given instance of a class, within
that method that object can be accessed via `$this` ([§§](#general-11)). As a
static method does not operate on a specific instance, it has no `$this`.
**Examples**
```
class Point
{
private static $pointCount = 0; // static property
private $x; // instance property
private $y; // instance property
public static function getPointCount() // static method
{
return self::$pointCount; // access static property
}
public function move($x, $y) // instance method
{
$this->x = $x;
$this->y = $y;
}
public function __construct($x = 0, $y = 0) // instance method
{
$this->x = $x; // access instance property
$this->y = $y; // access instance property
++self::$pointCount; // access static property
}
public function __destruct() // instance method
{
--self::$pointCount; // access static property
...
}
...
}
echo "Point count = " . Point::getPointCount() . "\n";
$cName = 'Point';
echo "Point count = " . $cName::getPointCount() . "\n";
```
# # Dynamic Members
Ordinarily, all of the instance properties and methods of a class are
declared explicitly in that class's definition. However, other
members—*dynamic properties* and, under certain circumstances, *dynamic
methods*—can be added to a particular instance of a class or to the
class as a whole at runtime. A dynamic property can also be removed from
an instance at runtime. In the case of dynamic properties, if a class
makes provision to do so by defining a series of special methods, it can
deal with the allocation and management of storage for those properties,
by storing them in another object or in a database, for example. (The
default behavior is for the Engine to allocate a VSlot for each one.)
This is called *class-specific dynamic allocation*. Otherwise, the
Engine takes care of the storage in some unspecified manner. Dynamic
method handling is only possible when ** class-specific dynamic
allocation is used.
Consider the following scenario, which involves dynamic properties:
```
class Point { ... } // has no public property "color", but has made
// provision to support dynamic properties.
$p = new Point(10, 15);
$p->color = "red"; // create/set the dynamic property "color"
$v = $p->color; // get the dynamic property "color"
isset($p->color); // test if the dynamic property "color" exists
unset($p->color); // remove the dynamic property "color"
```
For the ** class-specific dynamic allocation scenario, when a property
name that is not currently visible (because it is hidden or it does not
exist) is used in a modifiable lvalue context (as with the assignment of
"red"), the Engine generates a call to the instance method `__set`
([§§](#method-__set)). This method treats that name as designating a dynamic
property of the instance being operated on, and sets its value to "red",
creating the property, if necessary. Similarly, in a non-lvalue context,
(as with the assignment of color to $v), the Engine generates a call to
the instance method `__get` ([§§](#method-__get)), which treats that name as
designating a dynamic property of the instance being operated on, and
gets its value. In the case of the call to the intrinsic `isset`
([§§](#isset)), this generates a call to the instance method `__isset`
([§§](#method-__isset)), while a call to the intrinsic `unset` ([§§](#unset)) generates a
call to the instance method `__unset` ([§§](#method-__unset)). By defining these
four special methods, the implementer of a class can control how dynamic
properties are handled. For the non-class-specific dynamic allocation
scenario, the process is like that above except that no special `__*`
methods are called.
In the case of a dynamic method, no method is really added to the
instance or the class. However, the illusion of doing that is achieved
by allowing a call to an instance or static method, but one which is not
declared in that instance's class, to be accepted, intercepted by a
method called `__call` ([§§](#method-__call)) or `__callStatic` ([§§](#method-__callstatic)), and
dealt with under program control.
Consider the following code fragment, in which class Widget has neither
an instance method called `iMethod` nor a static method called `sMethod`,
but that class has made provision to deal with dynamic methods:
```
$obj = new Widget;
$obj->iMethod(10, TRUE, "abc");
Widget::sMethod(NULL, 1.234);
```
The call to `iMethod` is treated as if it were
```
$obj->__call('iMethod', array(10, TRUE, "abc"))
```
and the call to `sMethod` is treated as if it were
```
Widget::__callStatic('sMethod', array(NULL, 1.234))
```
# # Constants
**Syntax**
const-declaration:
const name = const-expression ;
*name* is defined in ([§§](#names)). *const-expression* is defined in
([§§](#constant-expressions)).
**Constraints:**
A *const-declaration* must only appear at the top level of a script, be
a *class constant* (inside a *class-definition*; [§§](#class-members)) or be an
*interface constant* (inside an *interface-definition;* [§§](#interface-members)).
A *const-declaration* must not redefine an existing c-constant ([§§](#general-4)).
A class constant must not have an explicit visibility specifier ([§§](#general-23)).
A class constant must not have an explicit `static` specifier.
**Semantics:**
A *const-declaration* defines a c-constant.
All class constants have public visibility.
All constants are implicitly `static`.
**Examples:**
```
const MIN_VAL = 20;
const LOWER = MIN_VAL;
// -----------------------------------------
class Automobile
{
const DEFAULT_COLOR = "white";
...
}
$col = Automobile::DEFAULT_COLOR;
```
# # Properties
**Syntax**
property-declaration:
property-modifier name property-initializeropt ;
property-modifier:
var
visibility-modifier static-modifieropt
static-modifier visibility-modifieropt
visibility-modifier:
public
protected
private
static-modifier:
static
property-initializer:
= constant-expression
*name* is described in [§§](#names) and *constant-expression* is described
in [§§](#constant-expressions).
**Semantics**
A *property-declaration* defines an instance or static property.
The visibility modifiers are described in [§§](#general-23). If
*visibility-modifier* is omitted, public is assumed. The var modifier
implies public visibility. The `static` modifier is described in [§§](#class-members).
The *property-initializer*s for instance properties are applied prior to
the class's constructor being called.
An instance property that is visible may be unset ([§§](#unset)), in which
case, the property is actually removed from that instance.
**Examples**
```
class Point
{
private static $pointCount = 0; // static property with initializer
private $x; // instance property
private $y; // instance property
...
}
```
# # Methods
**Syntax**
method-declaration:
method-modifiersopt function-definition
method-modifiers function-definition-header ;
method-modifiers:
method-modifier
method-modifiers method-modifier
method-modifier:
visibility-modifier
static-modifier
abstract
final
*visibility-modifier* is described in [§§](#general-23); *static-modifier* is
described in [§§](#class-members); and *function-definition* and
*function-definition-header* are defined in [§§](#function-definitions).
**Constraints**
When defining a concrete class that inherits from an abstract class, the
definition of each abstract method inherited by the derived class must
have the same or a
less-restricted [visibility](http://www.php.net/manual/en/language.oop5.visibility.php)
than in the corresponding abstract declaration. Furthermore, the
signature of a method definition must match that of its abstract
declaration.
The *method-modifiers* preceding a *function-definition* must not contain
the `abstract` modifier.
The *method-modifiers* preceding a *function-definition-header* must
contain the `abstract` modifier.
A method must not have the same modifier specified more than once. A
method must not have more than one *visibility-modifier*. A method must
not have both the modifiers `abstract` and `private`, or `abstract` and `final`.
**Semantics**
A *method-declaration* defines an instance or static method. A method is
a function that is defined inside a class. However, the presence of
`abstract` indicates an abstract method, in which case, no implementation
is provided. The absence of `abstract` indicates a concrete method, in
which case, an implementation is provided.
Method names are case-insensitive.
The presence of `final` indicates the method cannot be overridden in a
derived class.
If *visibility-modifier* is omitted, `public` is assumed.
**Examples**
See [§§](#class-members) for examples of instance and static methods. See [§§](#class-declarations) for
examples of abstract methods and their subsequent definitions.
# # Constructors
**Syntax**
constructor-definition:
visibility-modifier function &opt __construct ( parameter-declaration-listopt ) compound-statement
visibility-modifier function &opt name ( parameter-declaration-listopt ) compound-statement [Deprecated form]
*visibility-modifier* is described in [§§](#general-23);
*parameter-declaration-list* is described in [§§](#function-definitions); and
*compound-statement* is described in [§§](#compound-statements). *name* is described in
[§§](#names).
**Constraints**
An overriding constructor in a derived class must have the same or a
less-restricted [visibility](http://www.php.net/manual/en/language.oop5.visibility.php)
than that being overridden in the base class.
*name* must be the same as that in the *class-declaration* ([§§](#class-declarations)) that
contains this *constructor-definition*.
**Semantics**
A constructor is a specially named instance method ([§§](#methods)) that is used
to initialize an instance immediately after it has been created. Any
instance properties not explicitly initialized by a constructor take on
the value `NULL`. Like a method, a constructor can return a result by
value or byRef. (Unlike a method, a constructor cannot be abstract or
static.)
If *visibility-modifier* is omitted, `public` is assumed. A `private`
constructor inhibits the creation of an instance of the class type.
Constructors can be overridden in a derived class by redeclaring them.
However, an overriding constructor need not have the same signature as
defined in the base class.
Constructors are called by *object-creation-expression*s ([§§](#the-new-operator))
and from within other constructors.
If classes in a derived-class hierarchy have constructors, it is the
responsibility of the constructor at each level to call the constructor
in its base-class explicitly, using the notation
`parent::__construct(...)`. If a constructor calls its base-class
constructor, it should do so as the first statement in
*compound-statement*, so the object hierarchy is built from the
bottom-up. A constructor should not call its base-class constructor more
than once. A call to a base-class constructor searches for the nearest
constructor in the class hierarchy. Not every level of the hierarchy
need have a constructor.
Prior to the addition of the `__construct` form of constructor, a
class's constructor was called the same as its class name. For example,
class `Point`'s constructor was called `Point`. Although this old-style form
is supported, its use is deprecated. In any event, both
`parent::__construct(...)` and `parent::name(...)` (where `name` is the name
of the parent class type) will find an old- or a new-style constructor
in the base class, if one exists. If both forms exist, the new-style one
is used. The same is true of an *object-creation-expression* when
searching for a base-class constructor.
**Examples**
```
class Point
{
private static $pointCount = 0;
private $x;
private $y;
public function __construct($x = 0, $y = 0)
{
$this->x = $x;
$this->y = $y;
++self::$pointCount;
}
public function __destruct()
{
--self::$pointCount;
...
}
...
}
// -----------------------------------------
class MyRangeException extends Exception
{
public function __construct($message, ...)
{
parent::__construct($message);
...
}
...
}
```
# # Destructors
**Syntax**
destructor-definition:
visibility-modifier function &opt __destruct ( ) compound-statement
*visibility-modifier* is described in [§§](#general-23) and *compound-statement* is
described in [§§](#compound-statements).
**Constraints**
An overriding destructor in a derived class must have the same or a
less-restricted [visibility](http://www.php.net/manual/en/language.oop5.visibility.php)
than that being overridden in the base class.
**Semantics**
A destructor is a special-named instance method ([§§](#methods)) that is used to
free resources when an instance is no longer needed. The destructors for
instances of all classes are called automatically once there are no
handles pointing to those instances or in some unspecified order during
program shutdown. Like a method, a destructor can return a result by
value or byRef. (Unlike a method, a destructor cannot be abstract or
static.)
If *visibility-modifier* is omitted, `public` is assumed.
Destructors can be overridden in a derived class by redeclaring them.
Destructors are called by the Engine or from within other destructors.
If classes in a derived-class hierarchy have destructors, it is the
responsibility of the destructor at each level to call the destructor in
the base-class explicitly, using the notation `parent::__destruct()`. If
a destructor calls its base-class destructor, it should do so as the
last statement in *compound-statement*, so the object hierarchy is
destructed from the top-down. A destructor should not call its
base-class destructor more than once. A call to a base-class destructor
searches for the nearest destructor in the class hierarchy. Not every
level of the hierarchy need have a destructor. A `private` destructor
inhibits destructor calls from derived classes.
Any dynamic properties
([§](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12)14.4,
[§](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12)14.10.8)
having an object type, and whose parent instances exist when the program
terminates will have their destructors (if any) called as part of the
cleanup of the parent instances, even if the parent class type has no
destructor defined.
**Examples**
See [§§](#constructors) for an example of a constructor and destructor.
# # Methods with Special Semantics
## # General
If a class contains a definition for a method having one of the
following names, that method must have the prescribed visibility,
signature, and semantics:
Method Name | Description | Reference
------------|-------------|----------
`__call` | Calls a dynamic method in the context of an instance-method call | [§§](#method-__call)
`__callStatic` | Calls a dynamic method in the context of a static-method call | [§§](#method-__callstatic)
__clone |Typically used to make a deep copy ([§§](#)) of an object | [§§](#method-__clone)
`__construct` | A constructor | [§§](#constructors)
`__destruct` | A destructor | [§§](#destructors)
`__get` | Retrieves the value of a given dynamic property | [§§](#method-__get)
`__invoke` | Called when a script calls an object as a function | [§§](#method-__invoke)
`__isset` | Reports if a given dynamic property exists | [§§](#method-__isset)
`__set` | Sets the value of a given dynamic property | [§§](#method-__set)
`__set_state` | Called when a class is exported by `var_export` (§xx) | [§§](#method-__set_state)
`__sleep` | Executed before serialization ([§§](#serialization)) of an instance of this class | [§§](#method-__sleep)
`__toString` | Returns a string representation of the instance on which it is called | [§§](#method-__tostring)
`__unset` | Removes a given dynamic property | [§§](#method-__unset)
`__wakeup` | Executed after unserialization ([§§](#serialization)) of an instance of this class | [§§](#method-__wakeup)
## # Method `__call`
**Syntax**
public function __call ( $name , $arguments ) compound-statement*compound-statement* is described in [§§](#compound-statements). **Constraints** The argument corresponding to `$name` must have type `string`, and that corresponding to `$arguments` must have type `array`. The arguments passed to this method must not be passed byRef. **Semantics** This instance method is called to invoke the dynamic method ([§§](#dynamic-members)) designated by `$name` using the arguments specified by the elements of the array designated by `$arguments`. It can return any value deemed appropriate. Typically, `__call` is called implicitly, when the `->` operator ([§§](#member-selection-operator)) is used to call an instance method that is not visible. Now while `__call` can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression `p->m(...)`, where `p` is an instance and `m` is an instance-method name. If `m` is the name of a visible method, `p->m(...)` does not result in `__call`'s being called. Instead, the visible method is used. On the other hand, the expression `p->__call('m',array(...))` always calls the named dynamic method, ignoring the fact that a visible method having the same name might exist. If `m` is not the name of a visible method, the two expressions are equivalent; that is; when handling `p->m(...)`, if no visible method by that name is found, a dynamic method is assumed, and `__call` is called. (Note: While it would be unusual to create deliberately a dynamic method with the same name as a visible one, the visible method might be added later. This name "duplication" is convenient when adding a dynamic method to a class without having to worry about a name clash with any method names that class inherits.) While a method-name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic method name designated by *$name*. Any source character is allowed here. **Examples** ``` class Widget { public function __call($name, $arguments) { // using the method name and argument list, redirect/process // the method call, as desired. } ... } $obj = new Widget; $obj->iMethod(10, TRUE, "abc"); // $obj->__call('iMethod', array(...)) ``` ## # Method `__callStatic` **Syntax**
public static function __callStatic ( $name , $arguments ) compound-statement*compound-statement* is described in [§§](#compound-statements). **Constraints** The argument corresponding to `$name` must have type `string`, and that corresponding to `$arguments` must have type `array`. The arguments passed to this method must not be passed byRef. **Semantics** This static method is called to invoke the dynamic method ([§§](#dynamic-members)) designated by `$name` using the arguments specified by the elements of the array designated by `$arguments`. It can return any value deemed appropriate. Typically, `__callStatic` is called implicitly, when the `::` operator ([§§](#scope-resolution-operator)) is used to call a static method that is not visible. Now while `__callStatic` can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression `C::m(...)`, where `C` is a class and `m` is a static-method name. If `m` is the name of a visible method, `C::m(...)` does not result in `__callStatic`'s being called. Instead, the visible method is used. On the other hand, the expression `C::__callStatic('m',array(...))` always calls the named dynamic method, ignoring the fact that a static visible method having the same name might exist. If m is not the name of a visible method, the two expressions are equivalent; that is; when handling `C::m(...)`, if no visible method by that name is found, a dynamic method is assumed, and `__callStatic` is called. (Note: While it would be unusual to create deliberately a static dynamic method with the same name as a static visible one, the visible method might be added later. This name "duplication" is convenient when adding a dynamic method to a class without having to worry about a name clash with any method names that class inherits.) While a method-name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic method name designated by `$name`. Any source character is allowed here. **Examples** ``` class Widget { public static function __callStatic($name, $arguments) { // using the method name and argument list, redirect/process\ // the method call, as desired. } ... } Widget::sMethod(NULL, 1.234); // Widget::__callStatic('sMethod', array(...)) ``` ## # Method `__clone` **Syntax**
public function __clone ( ) compound-statement*compound-statement* is described in [§§](#compound-statements). **Semantics** This instance method is called by the `clone` operator ([§§](#the-clone-operator)), (typically) to make a deep copy ([§§](#)) of the current class component of the instance on which it is called. (Method `__clone` cannot be called directly by the program.) Consider a class `Employee`, from which is derived a class `Manager`. Let us assume that both classes contain properties that are objects. To make a copy of a `Manager` object, its `__clone` method is called to do whatever is necessary to copy the properties for the `Manager` class. That method should, in turn, call the `__clone` method of its parent class, `Employee`, so that the properties of that class can also be copied (and so on, up the derived-class hierarchy). To clone an object, the `clone` operator makes a shallow copy ([§§](#)) of the object on which it is called. Then, if the class of the instance being cloned has a method called `__clone`, that method is automatically called to make a deep copy. Method `__clone` cannot be called directly from outside a class; it can only be called by name from within a derived class, using the notation `self::__clone()`. This method can return a value; however, if it does so and control returns directly to the point of invocation via the `clone` operator, that value will be ignored. The value returned to a `self::__clone()` call can, however, be retrieved. While cloning creates a new object, it does so without using a constructor, in which case, code may need to be added to the `__clone` method to emulate what happens in a corresponding constructor. (See the `Point` example below.) An implementation of `__clone` should factor in the possibility of an instance having dynamic properties ([§§](#dynamic-members)). **Examples** ``` class Employee { ... public function __clone() { // do what it takes here to make a copy of Employee object properties } } class Manager extends Employee { ... public function __clone() { parent::__clone(); // request cloning of the Employee properties // do what it takes here to make a copy of Manager object properties } ... } // ----------------------------------------- class Point { private static $pointCount = 0; public function __construct($x = 0, $y = 0) { ... ++self::$pointCount; } public function __clone() { ++self::$pointCount; // emulate the constructor } ... } $p1 = new Point; // created using the constructor $p2 = clone $p1; // created by cloning ``` ## # Method `__get` **Syntax**
public function &opt __get ( $name ) compound-statement*compound-statement* is described in [§§](#compound-statements). **Constraints** The argument passed to this method must have type `string` and be passed by value. **Semantics** This instance method gets the value of the dynamic property ([§§](#dynamic-members)) designated by `$name`. If no such dynamic property currently exists, NULL is returned. Typically, `__get` is called implicitly, when the `->` operator ([§§](#member-selection-operator)) is used in a non-lvalue context and the named property is not visible. Now while `__get` can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression `$v = $p->m`, where `p` is an instance and `m` is a property name. If `m` is the name of a visible property, `p->m` does not result in `__get`'s being called. Instead, the visible property is used. On the other hand, the expression `p->__get('m')` always gets the value of the named dynamic property, ignoring the fact that a visible property having the same name might exist. If `m` is not the name of a visible property, the two expressions are equivalent; that is; when handling `p->m` in a non-lvalue context, if no visible property by that name is found, a dynamic property is assumed, and `__get` is called. Consider the expression $`v = $p->m = 5`, where `m` is a dynamic property. While `__set` ([§§](#method-__set)) is called to assign the value 5 to that property, `__get` is not called to retrieve the result after that assignment is complete. If the dynamic property is an array, `__get` should return byRef, so subscripting can be done correctly on the result. **Examples** ``` class Point { private $dynamicProperties = array(); private $x; private $y; public function __get($name) { if (array_key_exists($name, $this->dynamicProperties)) { return $this->dynamicProperties[$name]; } // no-such-property error handling goes here return NULL; } ... } ``` **Implementation Notes** Consider the following class, which does **not** contain a property called prop: ``` class C { public function __get($name) { return $this->$name; // must not recurse } ... } $c = new C; $x = $c->prop; ``` As no property (dynamic or otherwise) by the name prop exists in the class and a `__get` method is defined, this looks look a recursive situation. However, the implementation must not allow that. The same applies to seemingly self-referential implementations of `__set` ([§§](#method-__set)), `__isset` ([§§](#method-__isset)), and `__unset` ([§§](#method-__unset)). ## # Method `__invoke` **Syntax**
public function __invoke ( parameter-declaration-listopt ) compound-statement*parameter-declaration-list* is defined in [§§](#function-definitions); *compound-statement* is described in [§§](#compound-statements). **Semantics** This instance method allows an instance to be used with function-call notation. An instance whose class provides this method will return `TRUE` when passed to `is_callable` (§xx); otherwise, `FALSE` is returned. When an instance is called as a function, the argument list used is made available to `__invoke`, whose return value becomes the value of the initial function call. **Examples** ``` class C { public function __invoke($p) { ... return ...; } ... } $c = new C; is_callable($c) // returns TRUE $r = $c(123); // becomes $r = $c->__invoke(123); ``` ## # Method `__isset` **Syntax**
public function __isset ( $name ) compound-statement*compound-statement* is described in [§§](#compound-statements). **Constraints** The argument passed to this method must have type `string` and be passed by value. **Semantics** If the dynamic property ([§§](#dynamic-members)) designated by `$name` exists, this instance method returns `TRUE`; otherwise, `FALSE` is returned. Typically, `__isset` is called implicitly, when the intrinsic `isset` ([§§](#isset)) is called with an argument that designates a property that is not visible. (It can also be called by the intrinsic empty ([§§](#empty)).) Now while `__isset` can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression `isset($p->m)`, where `p` is an instance and `m` is a property name. If `m` is the name of a visible property, `__isset` is not called. Instead, the visible property is used. On the other hand, the expression `p->__isset('m')` always tests for the named dynamic property, ignoring the fact that a visible property having the same name might exist. If `m` is not the name of a visible property, the two expressions are equivalent; that is; when handling `p->m` in a non-lvalue context, if no visible property by that name is found, a dynamic property is assumed. **Examples** ``` class Point { private $dynamicProperties = array(); private $x; private $y; public function __isset($name) { return isset($this->dynamicProperties[$name]); } ... } ``` **Implementation Notes** See the Implementation Notes for `__get` ([§§](#method-__get)). ## # Method `__set` **Syntax**
public function __set ( $name , $value ) compound-statement*compound-statement* is described in [§§](#compound-statements). **Constraints** The arguments passed to this method must not be passed byRef. The argument corresponding to `$name` must have type `string`. **Semantics** This instance method sets the value of the dynamic property ([§§](#dynamic-members)) designated by `$name` to `$value`. If no such dynamic property currently exists, it is created. No value is returned. Typically, `__set` is called implicitly, when the `->` operator ([§§](#member-selection-operator)) is used in a modifiable lvalue context and the named property is not visible. Now while `__set` can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression `p->m = 5`, where `p` is an instance and `m` is a property name. If `m` is the name of a visible property, `p->m` does not result in `__set`'s being called. Instead, the visible property is used. On the other hand, the expression `p->__set('m',5)` always sets the value of the named dynamic property, ignoring the fact that a visible property having the same name might exist. If `m` is not the name of a visible property, the two expressions are equivalent; that is; when handling `p->m`, if no visible property by that name is found, a dynamic property is assumed, and `__set` is called. (Note: While it would be unusual to create deliberately a dynamic property with the same name as a visible one, the visible property might be added later. This name "duplication" is convenient when adding a dynamic property to a class without having to worry about a name clash with any property names that class inherits.) The parameter `$value` can have any type including an object type, and that type could have a destructor. Any dynamic properties of such types, whose parent instances exist when the program terminates will have their destructors called as part of the cleanup of the parent instances, even if the parent class type has no destructor defined. While a property-name source token has a prescribed syntax, there are no restrictions on the spelling of the dynamic property name designated by `$name`. Any source character is allowed here. **Examples** ``` class Point { private $dynamicProperties = array(); private $x; private $y; public function __set($name, $value) { $this->dynamicProperties[$name] = $value; } ... } // ----------------------------------------- class X { public function __destruct() { ... } } $p = new Point(5, 9); $p->thing = new X; // set dynamic property "thing" to instance with destructor ... // at the end of the program, p->thing's destructor is called ``` **Implementation Notes** See the Implementation Notes for `__get` ([§§](#method-__get)). ## # Method `__set_state` **Syntax**
static public function __set_state ( array $properties ) compound-statement*compound-statement* is described in [§§](#compound-statements). **Constraints** `$properties` must contain a key/value pair for each instance property in the class and all its direct and indirect base classes, where each key is the name of a property in that class. **Semantics** This function supports the library function `var_export` (§xx) when it is given an instance of this class type. `var_export` takes a variable and produces a string representation of that variable as valid PHP code suitable for use with the intrinsic `eval` ([§§](#eval)). For an object, the string returned by `var_export` has the following general format: `classname::__set_state(array('prop1' => value, ..., 'propN' => value , ))` where the property names `prop1` through `propN` do not include a leading dollar (`$`). This string contains a call to the `__set_state` method even if no such method is defined for this class or in any of its base classes, in which case, a subsequent call to `eval` using this string will fail. To allow the string to be used with eval, the method `__set_state` must be defined, and it must create a new instance of the class type, initialize its instance properties using the key/value pairs in `$properties`, and it must return that new object. If a derived class does not define a `__set_state` method, a call to it will look for such a method in the base class hierarchy, and that method will return an instance of the appropriate base class, not of the class on which it was invoked. This is probably not what the programmer expected. If a derived class defines a `__set_state` method, but any base class has instance properties that are not visible within that method, that method must invoke parent's `__set_state` as well, but that can require support from a base class. See the second example below. **Examples** ``` class Point { private $x; private $y; static public function __set_state(array $properties) { $p = new Point; $p->x = $properties['x']; $p->y = $properties['y']; return $p; } ... } $p = new Point(3, 5); $v = var_export($p, TRUE); // returns string representation of $p ``` The string produced looks something like the following: ``` "Point::__set_state(array( 'x' => 3, 'y' => 5, ))" eval('$z = ' . $v . ";"); // execute the string putting the result in $z echo "Point \$z is $z\n"; // Point $z is (3,5) // ----------------------------------------- class B // base class of D { private $bprop; public function __construct($p) { $this->bprop = $p; } static public function __set_state(array $properties) { $b = new static($properties['bprop']); // note the static return $b; // Because of the "new static", the return statement // returns a B when called in a B context, and // returns a D when called in a D context } } class D extends B { private $dprop = 123; public function __construct($bp, $dp = NULL) { $this->dprop = $dp; parent::__construct($bp); } static public function __set_state(array $properties) { $d = parent::__set_state($properties); // expects back a D, NOT a B $d->dprop = $properties['dprop']; return $d; } } $b = new B(10); $v = var_export($b, TRUE); eval('$z = ' . $v . ";"); $d = new D(20, 30); $v = var_export($d, TRUE); eval('$z = ' . $v . ";"); ``` ## # Method `__sleep` **Syntax**
public function __sleep ( ) compound-statement*compound-statement* is described in [§§](#compound-statements). **Semantics** The instance methods `__sleep` and `__wakeup` ([§§](#method-__wakeup)) support serialization ([§§](#serialization)). If a class has a `__sleep` method, the library function `serialize` (§xx) calls that method to find out which visible instance properties it should serialize. (In the absence of a `__sleep` or `serialize` method, all such properties are serialized, including any dynamic properties ([§§](#dynamic-members)).) This information is returned by `__sleep` as an array of zero or more elements, where each element's value is distinct and is the name of a visible instance property. These properties' values are serialized in the order in which the elements are inserted in the array. If `__sleep` does not return a value explicitly, `NULL` is returned, and that value is serialized. Besides creating the array of property names, `__sleep` can do whatever else might be needed before serialization occurs. Consider a `Point` class that not only contains x- and y-coordinates, it also has an `id` property; that is, each distinct `Point` created during a program's execution has a unique numerical id. However, there is no need to include this when a `Point` is serialized. It can simply be recreated when that `Point` is unserialized. This information is transient and need not be preserved across program executions. (The same can be true for other transient properties, such as those that contain temporary results or run-time caches.) In the absence of methods `__sleep` and `__wakeup`, instances of derived classes can be serialized and unserialized. However, it is not possible to perform customize serialization using those methods for such instances. For that, a class must implement the interface Serializable ([§§](#interface--serializable)). **Examples** ``` class Point { private static $nextId = 1; private $x; private $y; private $id; public function __construct($x = 0, $y = 0) { $this->x = $x; $this->y = $y; $this->id = self::$nextId++; // assign the next available id } public function __sleep() { return array('y', 'x'); // serialize only $y and $x, in that order } public function __wakeup() { $this->id = self::$nextId++; // assign a new id } ... } $p = new Point(-1, 0); $s = serialize($p); // serialize Point(-1,0) $v = unserialize($s); // unserialize Point(-1,0) ``` ## # Method `__toString` **Syntax**
public function __toString ( ) compound-statement*compound-statement* is described in [§§](#compound-statements). **Constraints** This function must return a string. This function must not throw any exceptions. **Semantics** This instance method is intended to create a string representation of the instance on which it is called. If the instance's class is derived from a class that has or inherits a `__toString` method, the result of calling that method should be prepended to the returned string. `__toString` is called by a number of language and library facilities, including `echo`, when an object-to-string conversion is needed. `__toString` can be called directly. An implementation of `__toString` should factor in the possibility of an instance having dynamic properties ([§§](#dynamic-members)). **Examples** ``` class Point { private $x; private $y; public function __construct($x = 0, $y = 0) { $this->x = $x; $this->y = $y; } public function __toString() { return '(' . $this->x . ',' . $this->y . ')'; } ... } $p1 = new Point(20, 30); echo $p1 . "\n"; // implicit call to __toString() returns "(20,30)" // ----------------------------------------- class MyRangeException extends Exception { public function __toString() { return parent::__toString() . string-representation-of-MyRangeException } ... } ``` ## # Method `__unset` **Syntax**
public function __unset ( $name ) compound-statement*compound-statement* is described in [§§](#compound-statements). **Constraints** The argument passed to this method must have type `string` and be passed by value. **Semantics** If the dynamic property ([§§](#dynamic-members)) designated by `$name` exists, it is removed by this instance method; otherwise, the call has no effect. No value is returned. Typically, `__unset` is called implicitly, when the intrinsic `unset` ([§§](#unset)) is called with an argument that designates a property that is not visible. Now while `__unset` can be called explicitly, the two scenarios do not necessarily produce the same result. Consider the expression `unset($p->m)`, where `p` is an instance and `m` is a property name. If `m` is the name of a visible property, `__unset` is not called. Instead, the visible property is used. On the other hand, the expression `p->__unset('m'))` always removes the named dynamic property, ignoring the fact that a visible property having the same name might exist. If `m` is not the name of a visible property, the two expressions are equivalent; that is; when handling `p->m` in a non-lvalue context, if no visible property by that name is found, a dynamic property is assumed. **Examples** ``` class Point { private $dynamicProperties = array(); private $x; private $y; public function __unset($name) { unset($this->dynamicProperties[$name]); } ... } ``` **Implementation Notes** See the Implementation Notes for `__get` ([§§](#method-__get)). ## # Method `__wakeup` **Syntax**
public function __wakeup ( ) compound-statement*compound-statement* is described in [§§](#compound-statements). **Constraints** Xx **Semantics** The instance methods `__sleep` ([§§](#method-__sleep)) and `__wakeup` support serialization ([§§](#serialization)). When the library function `unserialize` (§xx) is called on the string representation of an object, as created by the library function `serialize` (§xx), `unserialize` creates an instance of that object's type **without calling a constructor**, and then calls that class's `__wakeup` method, if any, to initialize the instance. In the absence of a `__wakeup` method, all that is done is that the values of the instance properties encoded in the serialized string are restored. Consider a `Point` class that not only contains x- and y-coordinates, it also has an `id` property; that is, each distinct `Point` created during a program's execution has a unique numerical id. However, there is no need to include this when a `Point` is serialized. It can simply be recreated by `__wakeup` when that `Point` is unserialized. This means that `__wakeup` must emulate the constructor, as appropriate. `__wakeup` does not return a value. **Examples** See [§§](#method-__sleep). # # Serialization In PHP, variables can be converted into some external form suitable for use in file storage or inter-program communication. The process of converting to this form is known as *serialization* while that of converting back again is known as *unserialization*. These facilities are provided by the library functions `serialize` (§xx) and `unserialize` (§xx), respectively. In the case of variables that are objects, on their own, these two functions serialize and unserialize all the instance properties, which may be sufficient for some applications. However, if the programmer wants to customize these processes, they can do so in one of two, mutually exclusive ways. The first approach is to define methods called `__sleep` and `__awake`, and have them get control before serialization and after serialization, respectively. For information on this approach, see [§§](#method-__sleep) and [§§](#method-__wakeup). The second approach involves implementing the interface `Serializable` ([§§](#interface--serializable)) by defining two methods, `serialize` and `unserialize`. Consider a `Point` class that not only contains x- and y-coordinates, it also has an `id` property; that is, each distinct `Point` created during a program's execution has a unique numerical id. However, there is no need to include this when a `Point` is serialized. It can simply be recreated when that `Point` is unserialized. This information is transient and need not be preserved across program executions. (The same can be true for other transient properties, such as those that contain temporary results or run-time caches.) Furthermore, consider a class `ColoredPoint` that extends `Point` by adding a `color` property. The following code shows how these classes need be defined in order for both `Points` and `ColoredPoints` to be serialized and unserialized: ``` class Point implements Serializable // note the interface { private static $nextId = 1; private $x; private $y; private $id; // transient property; not serialized public function __construct($x = 0, $y = 0) { $this->x = $x; $this->y = $y; $this->id = self::$nextId++; } public function __toString() { return 'ID:' . $this->id . '(' . $this->x . ',' . $this->y . ')'; } public function serialize() { return serialize(array('y' => $this->y, 'x' => $this->x)); } ``` The custom method `serialize` calls the library function `serialize` to create a string version of the array, whose keys are the names of the instance properties to be serialized. The insertion order of the array is the order in which the properties are serialized in the resulting string. The array is returned. ``` public function unserialize($data) { $data = unserialize($data); $this->x = $data['x']; $this->y = $data['y']; $this->id = self::$nextId++; } } ``` The custom method `unserialize` converts the serialized string passed to it back into an array. Because a new object is being created, but without any constructor being called, the `unserialize` method must perform the tasks ordinarily done by a constructor. In this case, that involves assigning the new object a unique id. ``` $p = new Point(2, 5); $s = serialize($p); ``` The call to the library function `serialize` calls the custom `serialize` method. Afterwards, the variable `$s` contains the serialized version of the `Point(2,5)`, and that can be stored in a database or transmitted to a cooperating program. The program that reads or receives that serialized string can convert its contents back into the corresponding variable(s), as follows: ``` $v = unserialize($s); ``` The call to the library function `unserialize` calls the custom `unserialize` method. Afterwards, the variable `$s` contains a new `Point(2,5)`. ``` class ColoredPoint extends Point implements Serializable { const RED = 1; const BLUE = 2; private $color; // an instance property public function __construct($x = 0, $y = 0, $color = RED) { parent::__construct($x, $y); $this->color = $color; } public function __toString() { return parent::__toString() . $this->color; } public function serialize() { return serialize(array( 'color' => $this->color, 'baseData' => parent::serialize() )); } ``` As with class `Point`, this custom method returns an array of the instance properties that are to be serialized. However, in the case of the second element, an arbitrary key name is used, and its value is the serialized version of the base Point within the current `ColoredPoint` object. The order of the elements is up to the programmer. ``` public function unserialize($data) { $data = unserialize($data); $this->color = $data['color']; parent::unserialize($data['baseData']); } } ``` As `ColoredPoint` has a base class, it unserializes its own instance properties before calling the base class's custom method, so it can unserialize the `Point` properties. ``` $cp = new ColoredPoint(9, 8, ColoredPoint::BLUE); $s = serialize($cp); ... $v = unserialize($s); ``` # # Predefined Classes # # # Class `Closure` The predefined class [`Closure`](http://www.php.net/manual/en/class.closure.php) is used for representing an [anonymous function](http://www.php.net/manual/en/functions.anonymous.php). It cannot be instantiated except by the Engine, as described below. ``` class Closure { public static bind(Closure $closure, $newthis [, $newscope = "static" ]); public bindTo($newthis [, $newscope = "static" ]); } ``` The class members are defined below: Name | Purpose -----|-------- `bind` | Duplicates closure `$closure` with a specific bound object `$newthis` and class scope `$newscope`. Make `$newthis` `NULL` if the closure is to be unbound. `$newscope` is the class scope to which the closure is to be associated, or static to keep the current one. If an object is given, the type of the object will be used instead. This determines the visibility of protected and private methods of the bound object. Returns a new `Closure` object or `FALSE` on failure. `bindTo` | Duplicates the closure designated by the current instance with a new-bound object and class scope. This method is an instance version of bind. When the anonymous function-creation operator ([§§](#anonymous-function-creation)) is evaluated, the result is an object of type `Closure` (or some unspecified class derived from that type) created by the Engine. This object is referred to here as "the Closure object". This instance encapsulates the anonymous function defined in the corresponding *anonymous-function-creation-expression*. The contents of a `Closure` object are determined based on the context in which an anonymous function is created. Consider the following scenario: ``` class C { public function compute() { $count = 0; $values = array("red" => 3, 10); $callback = function ($p1, $p2) use (&$count, $values) { ... }; ... } } ``` A `Closure` object may contain the following, optional dynamic properties, in order: `static`, `this`, and `parameter`. If an *anonymous-function-creation-expression* contains an *anonymous-function-use-clause*, a dynamic property called `static` is present. This property is an array having an element for each *variable-name* in the *use-variable-name-list*, inserted in lexical order of their appearance in the use clause. Each element's key is the corresponding *variable-name*, and each element value is the value of that variable at the time the time the `Closure` object is created (not when it is used to call the encapsulated function). In the scenario above, this leads to the following, shown as pseudo code: ``` $this->static = array(["count"]=>&0,["values"]=>array(["red"]=>3,[0]=>10)); ``` If an *anonymous-function-creation-expression* is used inside an instance method, a dynamic property called `this` is present. This property is a handle that points to the current instance. In the scenario above, this leads to the following, shown as pseudo code: ``` $this->this = $this; ``` If an *anonymous-function-creation-expression* contains a *parameter-declaration-list*, a dynamic property called `parameter` is present. This property is an array of one or more elements, each of which corresponds to a parameter. The elements are inserted in that array in lexical order of their declaration. Each element's key is the corresponding parameter name, and each element value is some unspecified value. (These values are overridden by the argument values used when the anonymous function is called.) In the scenario above, this leads to the following, shown as pseudo code: ``` $property = array("$p1" => ???, "$p2" => ???) ``` It is possible for all three dynamic properties to be absent, in which case, the `Closure` object is empty. ## # Class `Generator` This class supports the `yield` operator ([§§](#yield-operator)). This class cannot be instantiated directly. It is defined, as follows: class Generator implements Iterator ``` class Generator implements Iterator { public function current(); public function key(); public function next(); public function rewind(); public function send($value) ; public function throw(Exception $exception) ; public function valid(); public function __wakeup(); } ``` The class members are defined below: Name | Purpose ---- | ------- `current` | An implementation of the instance method `Iterator::current `([§§](#interface-iterator)). `key` | An implementation of the instance method `Iterator::key` ([§§](#interface-iterator)). next | An implementation of the instance method Iterator::next ([§§](#interface-iterator)). `rewind` | An implementation of the instance method `Iterator::rewind` ([§§](#interface-iterator)). `send` | This instance method sends the value designated by `$value` to the generator as the result of the current [`yield`](http://us2.php.net/manual/en/ language.generators.syntax.php#control-structures.yield) expression, and resumes execution of the generator. `$value` is the return value of the [`yield`](http://us2.php.net/manual/en/language.generators.syntax.php#control-structures.yield) expression the generator is currently at. If the generator is not at a [`yield`](http://us2.php.net/manual/en/language.generators.syntax.php#control-structures.yield) expression when this method is called, it will first be let to advance to the first [`yield`](http://us2.php.net/manual/en/language.generators.syntax.php#control-structures.yield) expression before sending the value. This method returns the yielded value. `throw` | This instance method throws an exception into the generator and resumes execution of the generator. The behavior is as if the current [`yield`](http://us2.php.net/manual/en/language.generators.syntax.php#control-structures.yield) expression was replaced with throw `$exception`. If the generator is already closed when this method is invoked, the exception will be thrown in the caller's context instead. This method returns the yielded value. `valid` | An implementation of the instance method `Iterator::valid` ([§§](#interface-iterator)). `__wakeup` | An implementation of the special instance method `__wakeup` ([§§](#method-__wakeup)). As a generator can't be serialized, this method throws an exception of an unspecified type. It returns no value. ## # Class `__PHP_Incomplete_Class` There are certain circumstances in which a program can generate an instance of this class, which on its own contains no members. One involves an attempt to unserialize ([§§](#method-__wakeup), [§§](#serialization)) a string that encodes an instance of a class for which there is no definition in scope. Consider the following class, which supports a two-dimensional Cartesian point: ``` class Point { private $x; private $y; ... } $p = new Point(2, 5); $s = serialize($p); // properties $x and $y are serialized, in that order ``` Let us assume that the serialized string is stored in a database from where it is retrieved by a separate program. That program contains the following code, but does not contain a definition of the class Point: ``` $v = unserialize($s); ``` Instead of returning a point, `Point(2, 5`), an instance of `__PHP_Incomplete_Class` results, with the following contents: ``` __PHP_Incomplete_Class { __PHP_Incomplete_Class_Name => "Point" x:Point:private => 2 y:Point:private => 5 } ``` The three dynamic properties ([§§](#dynamic-members)) contain the name of the unknown class, and the name, visibility, and value of each property that was serialized, in order of serialization. ## # Class `stdClass` This class contains no members. It can be instantiated and used as a base class. An instance of this type is automatically created when a non-object is converted to an object ([§§](#converting-to-object-type)), or the member-selection operator ([§§](#member-selection-operator)) is applied to `NULL`, `FALSE`, or an empty string. # Interfaces # # General A class can implement a set of capabilities—herein called a *contract*—through what is called an interface. An *interface* is a set of method declarations and constants. Note that the methods are only declared, not defined; that is, an interface defines a type consisting of abstract methods, where those methods are implemented by client classes as they see fit. An interface allows unrelated classes to implement the same facilities with the same names and types without requiring those classes to share a common base class. An interface can extend one or more other interfaces, in which case, it inherits all members from its *base interface(s)*. # # Interface Declarations **Syntax**
interface-declaration:
interface name interface-base-clauseopt { interface-member-declarationsopt }
interface-base-clause:
extends qualified-name
interface-base-clause , qualified-name
*name* and *qualified-name* are defined in [§§](#names).
*interface-member-declarations* is defined in [§§](#interface-members).
**Constraints**
An interface must not be derived directly or indirectly from itself.
*qualified-name* must name an interface type.
**Semantics**
An interface-declaration defines a contract that one or more classes can
implement.
Interface names are case-insensitive.
The optional *interface-base-clause* specifies the base interfaces from
which the interface being defined is derived. In such a case, the
derived interface inherits all the members from the base interfaces.
**Examples**
```
interface MyCollection
{
const MAX_NUMBER_ITEMS = 1000;
function put($item);
function get();
}
class MyList implements MyCollection
{
public function put($item) { /* implement method */ }
public function get() { /* implement method */ }
...
}
class MyQueue implements MyCollection
{
public function put($item) { /* implement method */ }
public function get() { /* implement method */ }
...
}
function processCollection(MyCollection $p1)
{
... /* can process any object whose class implements MyCollection
}
processCollection(new MyList(...));
processCollection(new MyQueue(...));
```
# # Interface Members
**Syntax**
interface-member-declarations:
interface-member-declaration
interface-member-declarations interface-member-declaration
interface-member-declaration:
const-declaration
method-declaration
*const-declaration* is defined in [§§](#constants-2) and *method-declaration* is
defined in [§§](#methods).
**Semantics**
The members of an interface are those specified by its
*interface-member-declaration*s, and the members inherited from its base
interfaces.
An interface may contain the following members:
- Constants – the constant values associated with the interface
([§§](#constants-3)).
- Methods – placeholders for the computations and actions that can be
performed by implementers of the interface ([§§](#methods-1)).
# # Constants
**Semantics:**
An interface constant is just like a class constant ([§§](#constants-2)), except that
an interface constant cannot be overridden by a class that implements it
nor by an interface that extends it.
**Examples:**
```
interface MyCollection
{
const MAX_NUMBER_ITEMS = 1000;
function put($item);
function get();
}
```
# # Methods
**Constraints**
All methods declared in an interface must be implicitly or explicitly
public, and they must not be declared `abstract`.
**Semantics:**
An interface method is just like an abstract method ([§§](#methods)).
**Examples:**
```
interface MyCollection
{
const MAX_NUMBER_ITEMS = 1000;
function put($item);
function get();
}
```
# # Predefined Interfaces
## # Interface `ArrayAccess`
This interface allows an instance of an implementing class to be
accessed using array-like notation. This interface is defined, as
follows:
```
interface ArrayAccess
{
function offsetExists($offset);
function offsetGet($offset);
function offsetSet($offset, $value);
function offsetUnset($offset);
}
```
The interface members are defined below:
Name | Purpose
---- | -------
`offsetExists` | This instance method returns `TRUE` if the instance contains an element with key `$offset`, otherwise, `FALSE`.
`offsetGet` | This instance method gets the value having key `$offset`. It may return by value or byRef. (Ordinarily, this wouldn't be allowed because a class implementing an interface needs to match the interface's method signatures; however, the Engine gives special treatment to `ArrayAccess` and allows this.) This method is called when an instance of a class that implements this interface is subscripted ([§§](#subscript-operator)) in a non-lvalue context.
`offsetSet` | This instance method sets the value having key `$offset` to $value. It returns no value. This method is called when an instance of a class that implements this interface is subscripted ([§§](#subscript-operator)) in a modifiable-lvalue context.
`offsetUnset` | This instance method unsets the value having key `$offset`. It returns no value.
## # Interface `Iterator`
This interface allows instances of an implementing class to be treated
as a collection. This interface is defined, as follows:
```
interface Iterator extends Traversable
{
function current();
function key();
function next();
function rewind();
function valid();
}
```
The interface members are defined below:
Name | Purpose
---- | -------
`current` | This instance method returns the element at the current position.
`key` |This instance method returns the key of the current element. On failure, it returns `NULL`; otherwise, it returns the scalar value of the key.
`next` | This instance method moves the current position forward to the next element. It returns no value. From within a `foreach` statement, this method is called after each loop.
`rewind` | This instance method resets the current position to the first element. It returns no value. From within a `foreach` statement, this method is called once, at the beginning.
`valid` | This instance method checks if the current position is valid. It takes no arguments. It returns a bool value of `TRUE` to indicate the current position is valid; `FALSE`, otherwise. This method is called after each call to [`Iterator::rewind()`](http://us2.php.net/manual/en/iterator.rewind.php) and [`Iterator::next()`](http://us2.php.net/manual/en/iterator.next.php).
## # Interface `IteratorAggregate`
This interface allows the creation of an external iterator. This
interface is defined, as follows:
```
Interface IteratorAggregate extends Traversable
{
function getIterator();
}
```
The interface members are defined below:
Name | Purpose
---- | -------
`getIterator` | This instance method retrieves an iterator, which implements `Iterator` or `Traversable`. It throws an `Exception` on failure.
## # Interface `Traversable`
This interface is intended as the base interface for all traversable
classes. This interface is defined, as follows:
```
Traversable
{
}
```
This interface has no members.
## # Interface `Serializable`
This interface provides support for custom serialization. It is defined,
as follows:
```
interface Serializable
{
function serialize();
function unserialize ($serialized);
}
```
The interface members are defined below:
Name | Purpose
-----| -------
`serialize` | This instance method returns a string representation of the current instance. On failure, it returns `NULL`.
`unserialize` | This instance method constructs an object from its string form designated by `$serialized`. It does not return a value.
# Traits
# # General
PHP's class model allows single inheritance only ([§§](#general-23)) with contracts
being enforced separately via interfaces ([§§](#general-25)). A *trait* can provide
both implementation and contracts. Specifically, a class can inherit
from a base class while getting implementation from one or more traits.
At the same time, that class can implement contracts from one or more
interfaces as well as from one or more traits. The use of a trait by a
class does not involve any inheritance hierarchy, so unrelated classes
can use the same trait. In summary, a trait is a set of methods and/or
state information that can be reused.
Traits are designed to support classes; a trait cannot be instantiated
directly.
The members of a trait each have visibility ([§§](#general-23)), which applies once
they are used by a given class. The class that uses a trait can change
the visibility of any of that trait's members, by either widening or
narrowing that visibility. For example, a private trait member can be
made public in the using class, and a pubic trait member can be made
private in that class.
Once implementation comes from both a base class and one or more traits,
name conflicts can occur. However, trait usage provides a means of
disambiguating such conflicts. Names gotten from a trait can also be
given aliases.
A class member with a given name overrides one with the same name in any
traits that class uses, which, in turn, overrides any such name from
base classes.
Traits can contain both instance and static members, including both
methods and properties. In the case of a trait with a static property,
each class using that trait has its own instance of that property.
Methods in a trait have full access to all members of any class in which
that trait is used.
# # Trait Declarations
**Syntax**
trait-declaration:
trait name { trait-use-clausesopt trait-member-declarationsopt }
trait-use-clauses:
trait-use-clause
trait-use-clauses trait-use-clause
trait-use-clause:
use trait-name-list trait-use-terminator
trait-name-list:
qualified-name
trait-name-list , qualified-name
trait-use-terminator:
;
{ trait-select-and-alias-clausesopt }
trait-select-and-alias-clauses:
trait-select-and-alias-clause
trait-select-and-alias-clauses trait-select-and-alias-clause
trait-select-and-alias-clause:
trait-select-insteadof-clause
trait-alias-as-clause
trait-select-insteadof-clause:
name insteadof name
trait-alias-as-clause:
name as visibility-modifieropt name
name as visibility-modifier nameopt
*name* is defined in [§§](#names); *visibility-modifier* is defined in
[§§](#properties); and *trait-member-declarations* is defined in [§§](#trait-members).
**Constraints**
The *name*s in *trait-name-list* must designate trait names, excluding
the name of the trait being declared.
The left-hand *name* in *trait-select-insteadof-clause* must
unambiguously designate a member of a trait made available by
*trait-use-clauses*. The right-hand *name* in
*trait-select-insteadof-clause* must unambiguously designate a trait
made available by *trait-use-clauses*.
The left-hand *name* in *trait-alias-as-clause* must unambiguously
designate a member of a trait made available by *trait-use-clauses*.
The right-hand *name* in *trait-alias-as-clause* must be a new,
unqualified name.
**Semantics**
A *trait-declaration* defines a named set of members, which are made
available to any class that uses that trait.
Trait names are case-insensitive.
A *trait-declaration* may also use other traits. This is done via one or
more *trait-use-clause*s, each of which contains a comma-separated list
of trait names. A *trait-use-clause* ends in a semicolon or a
brace-delimited set of *trait-select-insteadof-clause*s and
*trait-alias-as-clause*s.
A *trait-select-insteadof-clause* allows name clashes to be avoided.
Specifically, the left-hand *name* designates which name to be used from
of a pair of names. That is, `T1::compute insteadof T2`; indicates that
calls to method compute, for example, should be satisfied by a method of
that name in trait `T1` rather than `T2`.
A *trait-alias-as-clause* allows a (possibly qualified) name to be
assigned a simple alias name. Specifically, the left-hand *name* in
*trait-alias-as-clause* designates a name made available by
*trait-use-clauses* ~~ that is to be aliased, and the right-hand *name*
is the alias.
If *trait-alias-as-clause* contains a visibility-modifier, that controls
the visibility of the alias, if a right-hand name is provided;
otherwise, it controls the visibility of the left-hand name.
**Examples**
```
trait T1 { public function compute( ... ) { ... } }
trait T2 { public function compute( ... ) { ... } }
trait T1 { public function sort( ... ) { ... } }
trait T4
{
use T3;
use T1, T2
{
T1::compute insteadof T2; // disambiguate between two computes
T3::sort as private sorter; // make alias with adjusted visibility
}
}
```
# # Trait Members
**Syntax**
trait-member-declarations:
trait-member-declaration
trait-member-declarations trait-member-declaration
trait-member-declaration:
property-declaration
method-declaration
constructor-declaration
destructor-declaration
*property-declaration* is defined in [§§](#properties); *method-declaration* is
defined in [§§](#methods); *constructor-declaration* is defined in [§§](#names); and
*destructor-declaration* is defined in [§§](#destructors).
**Semantics**
The members of a trait are those specified by its
*trait-member-declaration*s, and the members from any other traits it
uses.
A trait may contain the following members:
- Properties – the variables made available to the class in which the
trait is used ([§§](#properties)).
- Methods – the computations and actions that can be performed by the
class in which the trait is used ([§§](#methods), [§§](#methods-with-special-semantics)).
- Constructor – the actions required to initialize an instance of the
class in which the trait is used ([§§](#constructors))
- Destructor – the actions to be performed when an instance of the
class in which the trait is used is no longer needed ([§§](#destructors)).
If a member has no explicit visibility, `public` is assumed.
**Examples**
```
trait T
{
private $prop1 = 1000;
protected static $prop2;
var $prop3;
public function compute( ... ) { ... }
public static function getData( ... ) { ... }
}
```
# Exception Handling
# # General
An *exception* is some unusual condition in that it is outside the
ordinary expected behavior. (Examples include dealing with situations in
which a critical resource is needed, but is unavailable, and detecting
an out-of-range value for some computation.) As such, exceptions require
special handling. This clause describes how exceptions can be created
and handled.
Whenever some exceptional condition is detected at runtime, an exception
is *thrown*. A designated exception handler can *catch* the thrown
exception and service it. Among other things, the handler might recover
from the situation completely (allowing the script to continue
execution), it might perform some recovery and then throw an exception
to get further help, or it might perform some cleanup action and
terminate the script. Exceptions may be thrown on behalf of the Engine
or by explicit code source code in the script.
Exception handling involves the use of the following keywords:
- `try` ([§§](#the-try-statement)), which allows a *try-block* of code containing one or
more possible exception generations, to be tried
- `catch` ([§§](#the-try-statement)), which defines a handler for a specific type of
exception thrown from the corresponding try-block or from some
function it calls
- `finally` ([§§](#the-try-statement)), which allows the *finally-block* of a try-block to
be executed (to perform some cleanup, for example), whether or not
an exception occurred within that try-block
- `throw` ([§§](#the-throw-statement)), which generates an exception of a given type, from
a place called a *throw point*
When an exception is thrown, an *exception object* of type `Exception`
([§§](#class-exception)), or of a subclass of that type, is created and made available to
the first catch-handler that can catch it. Among other things, the
exception object contains an *exception message* and an *exception
code*, both of which can be used by a handler to determine how to handle
the situation.
Prior to the addition of exception handling to PHP, exception-like
conditions were handled using Error Reporting (§xx). Now, errors can be
translated to exceptions via the class
[`ErrorException`](http://www.php.net/manual/en/class.errorexception.php)
(which is not part of this specification).
# # Class `Exception`
Class `Exception` is the base class of all exception types. This class is
defined, as follows:
```
Class Exception
{
private $string;
private $trace;
private $previous;
protected $message = 'Unknown exception';
protected $code = 0;
protected $file;
protected $line;
public function __construct($message = "", $code = 0,
Exception $previous = NULL);
final private function __clone();
final public function getMessage();
final public function getCode();
final public function getFile();
final public function getLine();
final public function getTrace();
final public function getPrevious();
final public function getTraceAsString();
public function __toString();
}
```
For information about exception trace-back, see [§§](#tracing-exceptions). For information
about nested exceptions, see [§§](#tracing-exceptions).
The class members are defined below:
Name | Purpose
---- | -------
`$code` | `int`; the exception code (as provided by the constructor)
`$file` | `string`; the name of the script where the exception was generated
`$line` | `int`; the source line number in the script where the exception was generated
`$message` | `string`; the exception message (as provided by the constructor)
`$previous` | The previous exception in the chain, if this is a nested exception; otherwise, `NULL`
`$string` | Work area for `__toString`
`$trace` | Work area for function-call tracing
`__construct` | Takes three (optional) arguments – `string`: the exception message (defaults to ""), `int`: the exception code (defaults to 0), and `Exception`: the previous exception in the chain (defaults to `NULL`)
`__clone` | Present to inhibit the cloning of exception objects
`__toString` | `string`; retrieves a string representation of the exception in some unspecified format
`getCode` | `mixed`; retrieves the exception code (as set by the constructor). For an exception of type Exception, the returned value has type int; for subclasses of `Exception`, it may have some other type.
`getFile` | `string`; retrieves the name of the script where the exception was generated
`getLine` | `int`; retrieves the source line number in the script where the exception was generated
`getMessage` | `string`; retrieves the exception message
`getPrevious` | `Exception`; retrieves the previous exception (as set by the constructor), if one exists; otherwise, `NULL`
`getTrace` | `array`; retrieves the function stack trace information as an array (see [§§](#tracing-exceptions))
`getTraceAsString` | `string`; retrieves the function stack trace information formatted as a single string in some unspecified format
# # Tracing Exceptions
When an exception is caught, the `get*` functions in class `Exception`
provide useful information. If one or more nested function calls were
involved to get to the place where the exception was generated, a record
of those calls is also retained, and made available by getTrace, through
what is referred to as the *function stack trace*, or simply, `*trace*`.
Let's refer to the top level of a script as *function-level* 0.
Function-level 1 is inside any function called from function-level 0.
Function-level 2 is inside any function called from function-level 1,
and so on. The library function `getTrace` returns an array. Exceptions
generated at function-level 0 involve no function call, in which case,
the array returned by `getTrace` has zero elements.
Each element of the array returned by `getTrace` provides information
about a given function level. Let us call this array *trace-array* and
the number of elements in this array *call-level*. The key for each of
trace-array's elements has type int, and ranges from 0 to
call-level - 1. For example, when a top-level script calls function `f1`,
which calls function `f2`, which calls function `f3`, which then generates
an exception, there are four function levels, 0–3, and there are three
lots of trace information, one per call level. That is, trace-array
contains three elements, and they each correspond to the reverse order
of the function calls. For example, trace-array[0] is for the call to
function `f3`, trace-array[1] is for the call to function `f2`, and
trace-array[2] is for the call to function `f1`.
Each element in trace-array is itself an array that contains elements
with the following key/value pairs:
Key | Value Type | Value
--- | ---------- | -----
"args" | `array` | The set of arguments passed to the function
"class" | `string` | The name of the function's parent class
"file" | `string` | The name of the script where the function was called
"function" | `string` | The name of the function or class method
"line" | `int` | The line number in the source where the function was called
"object" | `object` | The current object
"type" | `string` | Type of call; `->` for an instance method call, `::` for a static method call, ordinary function call, "" is returned.
As to whether extra elements with other keys are provided is
unspecified.
The key `args` has a value that is yet another array, which we shall
call *argument-array*. That array contains a set of values that
corresponds directly to the set of values passed as arguments to the
corresponding function. Regarding element order, argument-array[0]
corresponds to the left-most argument, argument-array[1] corresponds to
the next argument to the right, and so on.
Consider the case in which a function has a default argument value
defined for a parameter. If that function is called without an argument
for the parameter having the default value, no corresponding argument
exists in array-argument. Only arguments present at the function-call
site have their values recorded in array-argument.
See also, library functions `debug_backtrace` (§xx) and
`debug_print_backtrace` (§xx).
# # User-Defined Exception Classes
An exception class is defined simply by having it extend class `Exception`
([§§](#class-exception)). However, as that class's `__clone` method is declared `final`
([§§](#methods)), exception objects cannot be cloned.
When an exception class is defined, typically, its constructors call the
parent class' constructor as their first operation to ensure the
base-class part of the new object is initialized appropriately. They
often also provide an augmented implementation of
[`__toString()`](http://www.php.net/manual/en/language.oop5.magic.php)
([§§](#method-__tostring)).
# Namespaces
# # General
A problem encountered when managing large projects is that of avoiding
the use of the same name in the same scope for different purposes. This
is especially problematic in a language that supports modular design and
component libraries.
A *namespace* is a container for a set of (typically related)
definitions of classes, interfaces, traits, functions, and constants.
Namespaces serve two purposes:
- They help avoid name collisions.
- They allow certain long names to be accessed via shorter, more
convenient and readable, names.
A namespace may have *sub-namespaces*, where a sub-namespace name shares
a common prefix with another namespace. For example, the namespace
`Graphics` might have sub-namespaces `Graphics\D2` and `Graphics\D3`, for
two- and three-dimensional facilities, respectively. Apart from their
common prefix, a namespace and its sub-namespaces have no special
relationship. The namespace whose prefix is part of a sub-namespace need
not actually exist for the sub-namespace to exist. That is, `NS1\Sub` can
exist without `NS1`.
In the absence of any namespace definition, the names of subsequent
classes, interfaces, traits, functions, and constants are in the
*default namespace*, which has no name, per se.
The namespaces PHP, php, and sub-namespaces beginning with those
prefixes are reserved for use by PHP.
# # Name Lookup
When an existing name is used in source code, the Engine must determine
how that name is found with respect to namespace lookup. For this
purpose, names can have one of the three following forms:
- Unqualified name: Such names are just simple names without any
prefix, as in the class name `Point` in the following expression:
`$p = new Point(3,5)`. If the current namespace is `NS1`, the name
`Point` resolves to `NS1\Point`. If the current namespace is the
default namespace ([§§](#general-28)), the name `Point` resolves to `Point`. In the
case of an unqualified function or constant name, if that name does
not exist in the current namespace, a global function or constant by
that name is used.
- Qualified name: Such names have a prefix consisting of a namespace
name and/or one or more levels of sub-namespace names, and,
possibly, a class, interface, trait, function, or constant name.
Such names are relative. For example, `D2\Point` could be used to
refer to the class Point in the sub-namespace `D2` of the current
namespace. One special case of this is when the first component of
the name is the keyword `namespace`. This means "the current
namespace".
- Fully qualified name: Such names begin with a backslash (`\`) and are
followed optionally by a namespace name and one or more levels of
sub-namespace names, and, finally, a class, interface, trait,
function, or constant name. Such names are absolute. For example,
`\Graphics\D2\Point` could be used to refer unambiguously to the
class `Point` in namespace `Graphics`, sub-namespace `D2`.
The names of the standard types (such as `Exception`), constants (such as
`PHP_INT_MAX`), and library functions (such as `is_null`) are defined outside
any namespace. To refer unambiguously to such names, one can prefix them
with a backslash (`\`), as in `\Exception`, `\PHP_INT_MAX`, and `\is_null`.
# # Defining Namespaces
**Syntax**
namespace-definition:
namespace namespace-name ;
namespace namespace-nameopt compound-statement
*namespace-name* is defined in [§§](#names), and *compound-statement* is
defined in [§§](#compound-statements).
**Constraints**
Except for white space and an optional *declare-statement* ([§§](#the-declare-statement)), the
first occurrence of a *namespace-definition* in a script must be the
first thing in that script.
All occurrence of a *namespace-definition* in a script must have the
*compound-statement* form or must not have that form; the two forms
cannot be mixed.
When a script contains source code that is not inside a namespace, and
source code that is inside one or namespaces, the namespaced code must
use the *compound-statement* form of *namespace-definition*.
*compound-statement* must not contain a *namespace-definition*.
**Semantics**
Although a namespace may contain any PHP source code, the fact that that
code is contained in a namespace affects only the declaration and name
resolution of classes, interfaces, traits, functions, and constants.
Namespace and sub-namespace names are case-insensitive.
The pre-defined constant `__NAMESPACE__` ([§§](#context-dependent-constants)) contains the name of
the current namespace.
When the same namespace is defined in multiple scripts, and those
scripts are combined into the same program, the namespace is considered
the merger of its individual contributions.
The scope of the non-*compound-statement* form of *namespace-definition*
runs until the end of the script, or until the lexically next
*namespace-definition*, whichever comes first. The scope of the
*compound-statement* form is the *compound-statement*.
**Examples**
Script1.php:
```
namespace NS1;
... // __NAMESPACE__ is "NS1"
namespace NS3\Sub1;
... // __NAMESPACE__ is "NS3\Sub1"
```
Script2.php:
```
namespace NS1
{
... // __NAMESPACE__ is "NS1"
}
namespace
{
... // __NAMESPACE__ is ""
}
namespace NS3\Sub1;
{
... // __NAMESPACE__ is "NS3\Sub1"
}
```
# # Namespace Use Declarations**
**Syntax**
namespace-use-declaration:
use namespace-use-clauses ;
namespace-use-clauses:
namespace-use-clause
namespace-use-clauses , namespace-use-clause
namespace-use-clause:
qualified-name namespace-aliasing-clauseopt
namespace-aliasing-clause:
as name
*qualified-name* and *name* are defined in [§§](#names).
**Constraints**
A *namespace-use-declaration* must not occur except at the pseudomain
level or directly in the context of a *namespace-definition* (18.3).
If the same *qualified-name* is imported multiple times in the same
scope, each occurrence must have a different alias.
**Semantics**
*qualified-name* is always interpreted as referring to a class,
interface, or trait by that name. *namespace-use-clauses* can only
create aliases for classes, interfaces, or traits; it is not possible to
use them to create aliases to functions or constants.
A *namespace-use-declaration* *imports*—that is, makes available—one or
more names into a scope, optionally giving them each an alias. Each of
those names may designate a namespace, a sub-namespace, a class, an
interface, or a trait. If a namespace-alias-clause is present, its
*name* is the alias for *qualified-name*. Otherwise, the right-most name
in *qualified-name* is the implied alias for *qualified-name*.
**Examples**
```
namespace NS1
{
const CON1 = 100;
function f() { ... }
class C { ... }
interface I { ... }
trait T { ... }
}
namespace NS2
{
use \NS1\C, \NS1\I, \NS1\T;
class D extends C implements I
{
use T;
}
$v = \NS1\CON1; // explicit namespace still needed for constants
\NS1\f(); // explicit namespace still needed for functions
use \NS1\C as C2; // C2 is an alias for the class name \NS1\C
$c2 = new C2;
}
```
# Grammar
# # General
The grammar notation is described in [§§](#grammars).
# # Lexical Grammar
## # General
input-file::
input-element
input-file input-element
input-element::
comment
white-space
token
## # Comments
comment::
single-line-comment
delimited-comment
single-line-comment::
// input-charactersopt
# input-charactersopt
input-characters::
input-character
input-characters input-character
input-character::
Any source character except new-line
new-line::
Carriage-return character (U+000D)
Line-feed character (U+000A)
Carriage-return character (U+000D) followed by line-feed character (U+000A)
delimited-comment::
/* No characters or any source character sequence except /* */
## # White Space
white-space::
white-space-character
white-space white-space-character
white-space-character::
new-line
Space character (U+0020)
Horizontal-tab character (U+0009)
## # Tokens
### # General
token::
variable-name
name
keyword
literal
operator-or-punctuator
### # Names
variable-name::
$ name
namespace-name::
name
namespace-name \ name
namespace-name-as-a-prefix::
\
\opt namespace-name \
namespace \
namespace \ namespace-name \
qualified-name::
namespace-name-as-a-prefixopt name
name::
name-nondigit
name name-nondigit
name digit
name-nondigit::
nondigit
one of the characters U+007f–U+00ff
nondigit:: one of
_
a b c d e f g h i j k l m
n o p q r s t u v w x y z
A B C D E F G H I J K L M
N O P Q R S T U V W X Y Z
## # Keywords
keyword:: one of
abstract and as break callable case catch class clone
const continue declare default do echo else elseif
enddeclare endfor endforeach endif endswitch endwhile
extends final finally for foreach function global
goto if implements include include_once instanceof
insteadof interface namespace new or print private
protected public require require_once return static switch
throw trait try use var while xor yield
## # Literals
### # General
literal::
boolean-literal
integer-literal
floating-literal
string-literal
null-literal
### # Boolean Literals
boolean-literal::
TRUE (written in any case combination)
FALSE (written in any case combination)
### # Integer Literals
integer-literal::
decimal-literal
octal-literal
hexadecimal-literal
binary-literal
decimal-literal::
nonzero-digit
decimal-literal digit
octal-literal::
0
octal-literal octal-digit
hexadecimal-literal::
hexadecimal-prefix hexadecimal-digit
hexadecimal-literal hexadecimal-digit
hexadecimal-prefix:: one of
0x 0X
binary-literal::
binary-prefix binary-digit
binary-literal binary-digit
binary-prefix:: one of
0b 0B
digit:: one of
0 1 2 3 4 5 6 7 8 9
nonzero-digit:: one of
1 2 3 4 5 6 7 8 9
octal-digit:: one of
0 1 2 3 4 5 6 7
hexadecimal-digit:: one of
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F
binary-digit:: one of
0 1
### # Floating-Point Literals
floating-literal::
fractional-literal exponent-partopt
digit-sequence exponent-part
fractional-literal::
digit-sequenceopt . digit-sequence
digit-sequence .
exponent-part::
e signopt digit-sequence
E signopt digit-sequence
sign:: one of
+ -
digit-sequence::
digit
digit-sequence digit
### # String Literals
string-literal::
single-quoted-string-literal
double-quoted-string-literal
heredoc-string-literal
nowdoc-string-literal
single-quoted-string-literal::
bopt ' sq-char-sequenceopt '
sq-char-sequence::
sq-char
sq-char-sequence sq-char
sq-char::
sq-escape-sequence
\opt any member of the source character set except single-quote (') or backslash (\)
sq-escape-sequence:: one of
\' \\
double-quoted-string-literal::
bopt " dq-char-sequenceopt "
dq-char-sequence::
dq-char
dq-char-sequence dq-char
dq-char::
dq-escape-sequence
any member of the source character set except double-quote (") or backslash (\)
\ any member of the source character set except "\$efnrtvxX or
octal-digit
dq-escape-sequence::
dq-simple-escape-sequence
dq-octal-escape-sequence
dq-hexadecimal-escape-sequence
dq-simple-escape-sequence:: one of
\" \\ \$ \e \f \n \r \t \v
dq-octal-escape-sequence::
\ octal-digit
\ octal-digit octal-digit
\ octal-digit octal-digit octal-digit
dq-hexadecimal-escape-sequence::
\x hexadecimal-digit hexadecimal-digitopt
\X hexadecimal-digit hexadecimal-digitopt
heredoc-string-literal::
<<< hd-start-identifier new-line hd-char-sequenceopt new-line hd-end-identifier ;opt new-line
hd-start-identifier::
name
hd-end-identifier::
name
hd-char-sequence::
hd-char
hd-char-sequence hd-char
hd-char::
hd-escape-sequence
any member of the source character set except backslash (\)
\ any member of the source character set except \$efnrtvxX or
octal-digit
hd-escape-sequence::
hd-simple-escape-sequence
dq-octal-escape-sequence
dq-hexadecimal-escape-sequence
hd-simple-escape-sequence:: one of
\\ \$ \e \f \n \r \t \v
nowdoc-string-literal::
<<< ' hd-start-identifier ' new-line hd-char-sequenceopt new-line hd-end-identifier ;opt new-line
### # The Null Literal
null-literal::
NULL (written in any case combination)
## # Operators and Punctuators
operator-or-punctuator:: one of
[ ] ( ) { } . -> ++ -- ** * + - ~ !
$ / % << >> < > <= >= == === != !== ^ |
& && || ? : ; = **= *= /= %= += -= .= <<=
>>= &= ^= |= ,
# # Syntactic Grammar
## # Program Structure
script: script-section script script-section script-section: textopt <?php statement-listopt ?>opt textopt text: arbitrary text not containing the sequence <?php## # Variables
function-static-declaration:
static name function-static-initializeropt ;
function-static-initializer:
= const-expression
global-declaration:
global variable-name-list ;
variable-name-list:
expression
variable-name-list , expression
## # Expressions
### # Primary Expressions
primary-expression:
variable-name
qualified-name
literal
const-expression
intrinsic
anonymous-function-creation-expression
( expression )
$this
intrinsic:
array-intrinsic
echo-intrinsic
empty-intrinsic
eval-intrinsic
exit-intrinsic
isset-intrinsic
list-intrinsic
print-intrinsic
unset-intrinsic
array-intrinsic:
array ( array-initializeropt )
echo-intrinsic:
echo expression
echo ( expression )
echo expression-list-two-or-more
expression-list-two-or-more:
expression , expression
expression-list-two-or-more , expression
empty-intrinsic:
empty ( expression )
eval-intrinsic:
eval ( expression )
exit-intrinsic:
exit expressionopt
exit ( expressionopt )
die expressionopt
die ( expressionopt )
isset-intrinsic:
isset ( expression-list-one-or-more )
expression-list-one-or-more:
expression
expression-list-one-or-mor , expression
list-intrinsic:
list ( list-expression-listopt )
list-expression-list:
list-or-variable
,
list-expression-list , list-or-variableopt
list-or-variable:
list-intrinsic
expression
print-intrinsic:
print expression
print ( expression )
unset-intrinsic:
unset ( expression-list-one-or-more )
anonymous-function-creation-expression:
function &opt ( parameter-declaration-listopt ) anonymous-function-use-clauseopt
compound-statement
anonymous-function-use-clause:
use ( use-variable-name-list )
use-variable-name-list:
&opt variable-name
use-variable-name-list , &opt variable-name
### # Postfix Operators
postfix-expression:
primary-expression
clone-expression
object-creation-expression
array-creation-expression
subscript-expression
function-call-expression
member-selection-expression
postfix-increment-expression
postfix-decrement-expression
scope-resolution-expression
exponentiation-expression
clone-expression:
clone expression
object-creation-expression:
new class-type-designator ( argument-expression-listopt )
new class-type-designator
class-type-designator:
static
qualified-name
expression
array-creation-expression:
array ( array-initializeropt )
[ array-initializeropt ]
array-initializer:
array-initializer-list ,opt
array-initializer-list:
array-element-initializer
array-element-initializer , array-initializer-list
array-element-initializer:
&opt element-value
element-key => &opt element-value
element-key:
expression
element-value
expression
subscript-expression:
postfix-expression [ expressionopt ]
postfix-expression { expressionopt } [Deprecated form]
function-call-expression:
postfix-expression ( argument-expression-listopt )
argument-expression-list:
assignment-expression
argument-expression-list , assignment-expression
member-selection-expression:
postfix-expression -> member-selection-designator
member-selection-designator:
name
expression
postfix-increment-expression:
unary-expression ++
postfix-decrement-expression:
unary-expression --
scope-resolution-expression:
scope-resolution-qualifier :: member-selection-designator
scope-resolution-qualifier :: class
scope-resolution-qualifier:
qualified-name
expression
self
parent
static
exponentiation-expression:
expression ** expression
### # Unary Operators
unary-expression:
postfix-expression
prefix-increment-expression
prefix-decrement-expression
unary-op-expression
error-control-expression
shell-command-expression
cast-expression
variable-name-creation-expression
prefix-increment-expression:
++ unary-expression
prefix-decrement-expression:
-- unary-expression
unary-op-expression:
unary-operator cast-expression
unary-operator: one of
+ - ! \
error-control-expression:
@ expression
shell-command-expression:
` dq-char-sequenceopt `
cast-expression:
unary-expression
( cast-type ) cast-expression
cast-type: one of
array binary bool boolean double int integer float object
real string unset
variable-name-creation-expression:
$ expression
$ { expression }
### # instanceof Operator
instanceof-expression:
unary-expression
instanceof-subject instanceof instanceof-type-designator
instanceof-subject:
expression
instanceof-type-designator:
qualified-name
expression
### # Multiplicative Operators
multiplicative-expression:
instanceof-expression
multiplicative-expression * multiplicative-expression
multiplicative-expression / multiplicative-expression
multiplicative-expression % multiplicative-expression
### # Additive Operators
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
additive-expression . multiplicative-expression
### # Bitwise Shift Operators
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
### # Relational Operators
relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression
### # Equality Operators
equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
equality-expression <> relational-expression
equality-expression === relational-expression
equality-expression !== relational-expression
### # Bitwise Logical Operators
bitwise-AND-expression:
equality-expression
bit-wise-AND-expression & equality-expression
bitwise-exc-OR-expression:
bitwise-AND-expression
bitwise-exc-OR-expression ^ bitwise-AND-expression
bitwise-inc-OR-expression:
bitwise-exc-OR-expression
bitwise-inc-OR-expression | bitwise-exc-OR-expression
### # Logical Operators (form 1)
logical-AND-expression-1:
bitwise-incl-OR-expression
logical-AND-expression-1 && bitwise-inc-OR-expression
logical-inc-OR-expression-1:
logical-AND-expression-1
logical-inc-OR-expression-1 || logical-AND-expression-1
### # Conditional Operator
conditional-expression:
logical-inc-OR-expression-1
logical-inc-OR-expression-1 ? expressionopt : conditional-expression
### # Assignment Operators
assignment-expression:
conditional-expression
simple-assignment-expression
byref-assignment-expression
compound-assignment-expression
simple-assignment-expression:
unary-expression = assignment-expression
byref-assignment-expression:
unary-expression = & assignment-expression
compound-assignment-expression:
unary-expression compound-assignment-operator assignment-expression
compound-assignment-operator: one of
**= *= /= %= += -= .= <<= >>= &= ^= |=
### # Logical Operators (form 2)
logical-AND-expression-2:
assignment-expression
logical-AND-expression-2 and assignment-expression
logical-exc-OR-expression:
logical-AND-expression-2
logical-exc-OR-expression xor logical-AND-expression-2
logical-inc-OR-expression-2:
logical-exc-OR-expression
logical-inc-OR-expression-2 or logical-exc-OR-expression
### # yield Operator
yield-expression:
logical-inc-OR-expression-2
yield array-element-initializer
### # Script Inclusion Operators
expression:
yield-expression
include-expression
include-once-expression
require-expression
require-once-expression
include-expression:
include ( include-filename )
include include-filename
include-filename:
expression
include-once-expression:
include_once ( include-filename )
include_once include-filename
require-expression:
require ( include-filename )
require include-filename
require-once-expression:
require_once ( include-filename )
require_once include-filename
### # Constant Expressions
constant-expression:
array-creation-expression
const-expression
const-expression:
expression
## # Statements
### # General
statement:
compound-statement
labeled-statement
expression-statement
selection-statement
iteration-statement
jump-statement
declare-statement
const-declaration
function-definition
class-declaration
interface-declaration
trait-declaration
namespace-definition
namespace-use-declaration
global-declaration
function-static-declaration
### # Compound Statements
compound-statement:
{ statement-listopt }
statement-list:
statement
statement-list statement
### # Labeled Statements
labeled-statement:
named-label
case-label
default-label
named-label:
name : statement
case-label:
case expression case-default-label-terminator statement
default-label:
default case-default-label-terminator statement
case-default-label-terminator:
:
;
### # Expression Statements
expression-statement:
expressionopt ;
selection-statement:
if-statement
switch-statement
if-statement:
if ( expression ) statement elseif-clauses-1opt else-clause-1opt
if ( expression ) : statement-list elseif-clauses-2opt else-clause-2opt endif ;
elseif-clauses-1:
elseif-clause-1
elseif-clauses-1 elseif-clause-1
elseif-clause-1:
elseif ( expression ) statement
else-clause-1:
else statement
elseif-clauses-2:
elseif-clause-2
elseif-clauses-2 elseif-clause-2
elseif-clause-2:
elseif ( expression ) : statement-list
else-clause-2:
else : statement-list
switch-statement:
switch ( expression ) compound-statement
switch ( expression ) : statement-list endswitch;
### # Iteration Statements
iteration-statement:
while-statement
do-statement
for-statement
foreach-statement
while-statement:
while ( expression ) statement
while ( expression ) : statement-list endwhile ;
do-statement:
do statement while ( expression ) ;
for-statement:
for ( for-initializeropt ; for-controlopt ; for-end-of-loopopt ) statement
for ( for-initializeropt ; for-controlopt ; for-end-of-loopopt ) : statement-list endfor ;
for-initializer:
for-expression-group
for-control:
for-expression-group
for-end-of-loop:
for-expression-group
for-expression-group:
expression
for-expression-group , expression
foreach-statement:
foreach ( foreach-collection-name as foreach-keyopt foreach-value ) statement
foreach ( foreach-collection-name as foreach-keyopt foreach-value ) : statement-list endforeach ;
foreach-collection-name:
expression
foreach-key:
expression =>
foreach-value:
&opt expression
list-intrinsic
### # Jump Statements
jump-statement:
goto-statement
continue-statement
break-statement
return-statement
throw-statement
goto-statement:
goto name ;
continue-statement:
continue breakout-levelopt ;
breakout-level:
integer-literal
break-statement:
break breakout-levelopt ;
return-statement:
return expressionopt ;
throw-statement:
throw expression ;
### # The try Statement
try-statement:
try compound-statement catch-clauses
try compound-statement finally-clause
try compound-statement catch-clauses finally-clause
catch-clauses:
catch-clause
catch-clauses catch-clause
catch-clause:
catch ( parameter-declaration-list ) compound-statement
finally-clause:
finally compound-statement
### # The declare Statement
declare-statement:
declare ( declare-directive ) statement
declare ( declare-directive ) : statement-list enddeclare ;
declare ( declare-directive ) ;
declare-directive:
ticks = declare-tick-count
encoding = declare-character-encoding
declare-tick-count
expression
declare-character-encoding:
expression
## # Functions
function-definition:
function-definition-header compound-statement
function-definition-header:
function &opt name ( parameter-declaration-listopt )
parameter-declaration-list:
parameter-declaration
parameter-declaration-list , parameter-declaration
parameter-declaration:
type-hintopt &opt variable-name default-argument-specifieropt
type-hint:
array
callable
qualified-name
default-argument-specifier:
= const-expression
## # Classes
class-declaration:
class-modifieropt class name class-base clauseopt class-interface-clauseopt { trait-use-clausesopt class-member-declarationsopt }
class-modifier:
abstract
final
class-base-clause:
extends qualified-name
class-interface-clause:
implements qualified-name
class-interface-clause , qualified-name
class-member-declarations:
class-member-declaration
class-member-declarations class-member-declaration
class-member-declaration:
const-declaration
property-declaration
method-declaration
constructor-declaration
destructor-declaration
const-declaration:
const name = const-expression ;
property-declaration:
property-modifier name property-initializeropt ;
property-modifier:
var
visibility-modifier static-modifieropt
static-modifier visibility-modifieropt
visibility-modifier:
public
protected
private
static-modifier:
static
property-initializer:
= constant-expression
method-declaration:
method-modifiersopt function-definition
method-modifiers function-definition-header ;
method-modifiers:
method-modifier
method-modifiers method-modifier
method-modifier:
visibility-modifier
static-modifier
abstract
final
constructor-definition:
visibility-modifier function &opt __construct ( parameter-declaration-listopt ) compound-statement
visibility-modifier function &opt name ( parameter-declaration-listopt ) compound-statement [Deprecated form]
destructor-definition:
visibility-modifier function &opt __destruct ( ) compound-statement
## # Interfaces
interface-declaration:
interface name interface-base-clauseopt { interface-member-declarationsopt }
interface-base-clause:
extends qualified-name
interface-base-clause , qualified-name
interface-member-declarations:
interface-member-declaration
interface-member-declarations interface-member-declaration
interface-member-declaration:
const-declaration
method-declaration
## # Traits
trait-declaration:
trait name { trait-use-clausesopt trait-member-declarationsopt }
trait-use-clauses:
trait-use-clause
trait-use-clauses trait-use-clause
trait-use-clause:
use trait-name-list trait-use-terminator
trait-name-list:
qualified-name
trait-name-list , qualified-name
trait-use-terminator:
;
{ trait-select-and-alias-clausesopt }
trait-select-and-alias-clauses:
trait-select-and-alias-clause
trait-select-and-alias-clauses trait-select-and-alias-clause
trait-select-and-alias-clause:
trait-select-insteadof-clause
trait-alias-as-clause
trait-select-insteadof-clause:
name insteadof name
trait-alias-as-clause:
name as visibility-modifieropt name
name as visibility-modifier nameopt
trait-member-declarations:
trait-member-declaration
trait-member-declarations trait-member-declaration
trait-member-declaration:
property-declaration
method-declaration
constructor-declaration
destructor-declaration
## # Namespaces
namespace-definition:
namespace namespace-name ;
namespace namespace-nameopt compound-statement
namespace-use-declaration:
use namespace-use-clauses ;
namespace-use-clauses:
namespace-use-clause
namespace-use-clauses , namespace-use-clause
namespace-use-clause:
qualified-name namespace-aliasing-clauseopt
namespace-aliasing-clause:
as name
# Bibliography
The following documents are useful references for implementers and users
of this specification:
IEC 60559:1989, *Binary floating-point arithmetic for microprocessor
systems* (previously designated IEC 559:1989). (This standard is widely
known by its U.S. national designation, ANSI/IEEE Standard 754-1985,
IEEE Standard for Binary Floating-Point Arithmetic.)
The Unicode Consortium. *The Unicode Standard, Version 5.0*,
[www.Unicode.org](http://www.Unicode.org)).
================================================
FILE: tests/.hhconfig
================================================
================================================
FILE: tests/Attributes/.hhconfig
================================================
================================================
FILE: tests/Attributes/__ConsistentConstruct.php
================================================
>
class Base {
public function __construct() {
echo "In " . __METHOD__ . "\n";
}
public static function make(): this {
echo "making a new object\n";
return new static();
}
}
class Derived extends Base {
public function __construct(...) {
echo "In " . __METHOD__ . "\n";
parent::__construct();
}
}
// --------------------------------------------------------
// test with constructors having no 2 arguments, and override being variadic
<<__ConsistentConstruct>>
class C1 {
public function __construct(int $p1, float $p2) {
echo "In " . __METHOD__ . "\n";
}
public static function make(): this {
echo "making a new object\n";
return new static(123, 6.5);
}
}
<<__ConsistentConstruct>>
class C2 extends C1 {
public function __construct(int $p1, float $p2, ...) {
echo "In " . __METHOD__ . "\n";
parent::__construct($p1, $p2);
}
}
/*
// --------------------------------------------------------
// use UNSAFE_Construct attribute
<<__ConsistentConstruct>>
class Base2 {
public function __construct() {
echo "In " . __METHOD__ . "\n";
}
public static function make(): this {
echo "making a new object\n";
return new static();
}
}
class Derived2 extends Base2 {
<