<?xml version="1.0" encoding="UTF-8"?>
<syntax name="php">
	<zones>
		<!-- PHP Source Block; <?php ... ?> -->
		<zone name="embedded.language-root.php">
			<starts-with>
				<expression>(&lt;)(\?)(php|=)?</expression>
				<capture number="0" name="delimiter.source.start"/>
				<capture number="1" name="punctuation.bracket.angle.open" />
				<capture number="2" name="punctuation.delimiter.question-mark" />
				<capture number="3" name="keyword.definition" />
			</starts-with>
			<ends-with>
				<expression>(\?)(>)</expression>
				<capture number="0" name="delimiter.source.end"/>
				<capture number="1" name="punctuation.delimiter.question-mark"/>
				<capture number="2" name="punctuation.bracket.angle.close" />
			</ends-with>
			<subzones>
				<include collection="language" />
			</subzones>
		</zone>
	</zones>
	
	<library>
		<!-- Typically this isn't necessary, but because we need to embed the language in a couple places and "self" requires new PHP delimiters, it's a required hack -->
		<collection name="language">
			<include collection="comments" />
			<include collection="strings" />
			<include collection="shell-executables" />
			<include collection="functions" />
			<include collection="classes" />
			<include collection="switch-blocks" />
			<include collection="keywords" />
			<include collection="variables" />
			<include collection="punctuation" />
		</collection>
		
		<!--Comments-->
		<collection name="comments">
			<!-- Inline documentation style comments -->
			<zone name="comment.block.documentation">
				<starts-with>
					<expression>/\*(?:(?!\*/)[*!](?:\*(?!/$)|/(?!$))*|\s*(?:[*#=~+-]{3,}(?!/)|!)|(?=.*?\b(?i:FIX ?ME|TODO)\b))</expression>
					<capture number="0" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>\*/</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
				<subzones>
					<zone>
						<expression>(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()&lt;>]+|\((?:[^\s()&lt;>]+|(?:\([^\s()&lt;>]+\)))*\))+(?:\((?:[^\s()&lt;>]+|(?:\([^\s()&lt;>]+\)))*\)|[^\s`!()\[\]{};:'".,&lt;>?«»“”‘’]))|(?&lt;=\s|^)(@[a-z]+\b|\bFIX ?ME\b|\bTODO\b)</expression>
						<capture number="1" name="markup.link"/>
						<capture number="2" name="keyword"/>
					</zone>
				</subzones>
			</zone>
			<zone name="comment.line.documentation">
				<expression>((?://|#)[!/#]?)(?:(?&lt;=//[!/#]|#[!/#])|\s*(?:[*#=~+-]{3,}|!)|.*?\b(?i:FIX ?ME|TODO)\b).*?(?:(?=\?>)|$[\n\r]*)</expression>
				<capture number="1" name="punctuation.definition.begin"/>
				<subzones>
					<zone name="keyword">
						<expression>\b(?i:FIX ?ME|TODO)\b</expression>
					</zone>
				</subzones>
			</zone>
			<!-- Basic comments -->
			<zone name="comment.block">
				<starts-with>
					<expression>/\*</expression>
					<capture number="0" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>\*/</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
			</zone>
			<zone name="comment.line">
				<expression>(//|#).*?(?:(?=\?>)|$[\n\r]*)</expression>
				<capture number="1" name="punctuation.definition.begin"/>
			</zone>
		</collection>
		
		<!--Strings-->
		<collection name="strings">
			<!--Standard strings-->
			<zone name="string.quoted">
				<starts-with>
					<expression>"</expression>
					<capture number="0" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>"</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
				<subzones>
					<include collection="quoted-variables" />
					<include collection="character-escapes" />
				</subzones>
			</zone>
			<zone name="string.quoted">
				<starts-with>
					<expression>'</expression>
					<capture number="0" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>'</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
				<subzones>
					<zone name="constant.character.escape">
						<expression>\\(?:'|\\)</expression>
					</zone>
				</subzones>
			</zone>
			<!--heredoc-->
			<zone name="string.block.heredoc">
				<starts-with>
					<expression>(&lt;{3})("?)(\w+)\2$</expression>
					<capture number="0" name="delimiter.heredoc.start"/>
					<capture number="1" name="punctuation.definition.begin" />
					<capture number="3" name="token.identifier" />
				</starts-with>
				<ends-with>
					<expression>^(\3)(;?)$</expression>
					<capture number="0" name="delimiter.heredoc.end" />
					<capture number="1" name="token.identifier"/>
					<capture number="2" name="punctuation.x-semicolon"/>
				</ends-with>
				<subzones>
					<include collection="quoted-variables" />
					<include collection="character-escapes" />
				</subzones>
			</zone>
			<!--nowdoc-->
			<zone name="string.block.nowdoc">
				<starts-with>
					<expression>(&lt;{3})'(\w+)'$</expression>
					<capture number="0" name="delimiter.nowdoc.start"/>
					<capture number="1" name="punctuation.definition.begin"/>
					<capture number="2" name="token.identifier"/>
				</starts-with>
				<ends-with>
					<expression>^(\2)(;?)$</expression>
					<capture number="0" name="delimiter.nowdoc.end" />
					<capture number="1" name="token.identifier"/>
					<capture number="2" name="punctuation.x-semicolon"/>
				</ends-with>
			</zone>
		</collection>
		
		<!--Character Escapes-->
		<collection name="character-escapes">
			<zone name="constant.character.escape">
				<expression>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)</expression>
			</zone>
		</collection>
		
		<!--Legal variables for double-quoted strings-->
		<collection name="quoted-variables">
			<!--Simple variables with optional arrays/properties-->
			<zone>
				<expression>((\$+)[a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*)((?:\[(?:[0-9]+|[a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*)\]|->[a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*)*)|(\$)(\{)[a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*(\})</expression>
				<!--Simple variables-->
				<capture number="1" name="variable"/>
				<capture number="2" name="punctuation"/>
				<capture number="3" name="x-accessor">
					<subzones>
						<zone>
							<expression>(\[)(?:([0-9]+)|([a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*))(\])|(->)[a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*</expression>
							<!--Array indexes-->
							<capture number="1" name="punctuation.brace.square.open"/>
							<capture number="2" name="constant.numeric"/>
							<capture number="3" name="identifier.index"/>
							<capture number="4" name="punctuation.brace.square.close"/>
							<!--Properties-->
							<capture number="5" name="punctuation"/>
							<capture number="6" name="variable.property"/>
						</zone>
					</subzones>
				</capture>
				<!--Complex variables: ${variable}-->
				<capture number="4" name="punctuation"/>
				<capture number="5" name="punctuation.brace.curly.open"/>
				<capture number="6" name="punctuation.brace.curly.close"/>
			</zone>
			<!--{$expression}-->
			<zone name="expression.complex">
				<starts-with>
					<expression>(\{)(?=\$)</expression>
					<capture number="1" name="punctuation.brace.curly.open"/>
				</starts-with>
				<ends-with>
					<expression>\}</expression>
					<capture number="0" name="punctuation.brace.curly.close"/>
				</ends-with>
				<subzones>
					<include collection="strings" />
					<include collection="functions" />
					<include collection="classes" />
					<include collection="keywords" />
					<include collection="variables" />
					<include collection="punctuation" />
				</subzones>
			</zone>
		</collection>
		
		<!--Shell executable blocks-->
		<collection name="shell-executables">
			<zone name="string.executable.code">
				<starts-with>
					<expression>`</expression>
					<capture number="0" name="punctuation.definition.begin"/>
				</starts-with>
				<ends-with>
					<expression>`</expression>
					<capture number="0" name="punctuation.definition.end"/>
				</ends-with>
				<subzones>
					<include collection="quoted-variables" />
					<zone name="constant.character.escape">
						<expression>\\`</expression>
					</zone>
				</subzones>
			</zone>
		</collection>
		
		<!--Keywords and constants-->
		<collection name="keywords">
			<zone>
				<expression>\b(?:((?i:true|false|null))|(case|cfunction|class|continue|declare|default|else\s*if|function|goto|interface|old_function|namespace|use|trait)|(switch|break|do|else|if|for|foreach|as|(?:end(?:declare|for(?:each)?|if|switch|while)))|(const|var)|(abstract|global|final|private|protected|public|static(?!::))|(catch|try|throw|exception)|(new|clone)|((?i:and|or|xor))|(array|die|echo|empty|exit|eval|include(?:_once)?|isset|list|require(?:_once)?|return|print|unset)|([0-9]+\.?[0-9]*(?:[eE]-?[0-9]+)?|0(?:x|X)[0-9a-fA-F]+))\b</expression>
				<capture number="1" name="constant.language"/>
				<capture number="2" name="keyword.control"/>
				<capture number="3" name="keyword.control" behavior="text-to-name" behavior-match="^((?:end)?)" behavior-transform="(?1:alternate-end.:)x-$0" />
				<capture number="4" name="keyword.storage.type"/>
				<capture number="5" name="keyword.modifier.scope"/>
				<capture number="6" name="keyword.control.exception"/>
				<capture number="7" name="keyword.operator"/>
				<capture number="8" name="operator.logical"/>
				<capture number="9" name="keyword.language.function"/>
				<capture number="10" name="constant.numeric"/>
			</zone>
		</collection>
		
		<!--Switch blocks-->
		<collection name="switch-blocks">
			<zone name="x-item-start.x-case">
				<starts-with>
					<expression>\b(?:case|default)\b</expression>
					<capture number="0" name="keyword.control"/>
				</starts-with>
				<ends-with>
					<expression>:|;</expression>
					<capture number="0" name="punctuation" behavior="text-to-name" behavior-match="(:)|(;)" behavior-transform="x-(?1:colon:)(?2:semicolon:)" />
				</ends-with>
				<subzones>
					<include collection="comments" />
					<include collection="strings" />
					<include collection="keywords" />
					<include collection="variables" />
					<include collection="punctuation" />
				</subzones>
			</zone>
		</collection>
		
		<!--Functions-->
		<collection name="functions">
			<!-- function doSomething(...) { ... } -->
			<zone>
				<expression>\b(((?:(?:public|protected|private|static)[ \t]+)*)(function)\s+([a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*)\s*)(\()</expression>
				<capture number="1" name="function.definition"/>
				<capture number="2">
					<subzones>
						<zone name="keyword.modifier.scope">
							<expression>\b(private|protected|public|static)\b</expression>
						</zone>
					</subzones>
				</capture>
				<capture number="3" name="keyword.control"/>
				<capture number="4" name="name"/>
				<capture number="5" name="punctuation.brace.round.open"/>
			</zone>
		</collection>
		
		<!--Classes-->
		<collection name="classes">
			<!-- class MyClass { ... } -->
			<!--This is technically incorrect; interfaces cannot use 'implements'. But honestly, who cares?-->
			<zone name="class.definition">
				<starts-with>
					<expression>\b(class|interface|trait)\s+([a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*)</expression>
					<capture number="1" name="keyword.control"/>
					<capture number="2" name="name"/>
				</starts-with>
				<ends-with>
					<expression>(?=\{)</expression>
				</ends-with>
				<subzones>
					<zone name="keyword.inheritance">
						<expression>\b(extends|implements)\b</expression>
					</zone>
					<zone name="variable.class.parent">
						<expression>\b[a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*\b</expression>
					</zone>
					<zone name="punctuation.x-comma">
						<expression>,</expression>
					</zone>
				</subzones>
			</zone>
			<!--new MyClass();-->
			<zone>
				<expression>(?i)\b(new)\s+((\$?)[a-zA-Z_\u7f-\uff\\][a-zA-Z0-9_\u7f-\uff\\]*)|\b(instanceof)\s+([a-zA-Z_\u7f-\uff\\][a-zA-Z0-9_\u7f-\uff\\]*)</expression>
				<capture number="1" name="keyword.operator.new"/>
				<capture number="2" name="variable.class"/>
				<capture number="3" name="punctuation"/>
				<!--instanceof operator-->
				<capture number="4" name="keyword.operator"/>
				<capture number="5" name="variable.class"/>
			</zone>
		</collection>
		
		<!--Variables-->
		<collection name="variables">
			<!--alternate string character index access-->
			<zone name="x-accessor">
				<starts-with>
					<expression>((\$*)[a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*)(\{)</expression>
					<capture number="1" name="variable" />
					<capture number="2" name="punctuation"/>
					<capture number="3" name="punctuation.brace.curly.open"/>
				</starts-with>
				<ends-with>
					<expression>\}</expression>
					<capture number="0" name="punctuation.brace.curly.close"/>
				</ends-with>
				<subzones>
					<include collection="comments" />
					<include collection="strings" />
					<include collection="keywords" />
					<include collection="variables" />
					<include collection="punctuation" />
				</subzones>
			</zone>
			<!-- ->{compound-property} -->
			<zone name="x-property">
				<starts-with>
					<expression>\s*(->)\s*(\{)</expression>
					<capture number="1" name="punctuation.x-arrow"/>
					<capture number="2" name="punctuation.brace.curly.open"/>
				</starts-with>
				<ends-with>
					<expression>\s*(\})</expression>
					<capture number="1" name="punctuation.brace.curly.close"/>
				</ends-with>
				<subzones>
					<include collection="comments" />
					<include collection="strings" />
					<include collection="keywords" />
					<include collection="variables" />
					<include collection="punctuation" />
				</subzones>
			</zone>
			<zone>
				<expression>((\$*)[a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*)(::)(?:((\$?)[a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*)\s*(\()|((\$?)[a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*))|\s*(->)\s*(?:((\$?)[a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*)\s*(\()|((\$?)[a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*))|([a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*)\s*(\()|((\$)this)\b|((\$)(?:argc|argv|php_errormsg|HTTP_RAW_POST_DATA|http_response_header|GLOBALS|_(?:COOKIE|ENV|FILES|GET|POST|REQUEST|SERVER|SESSION)))\b|((\$+)[a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*)|((\$\{)(.*?)(\}))|([a-zA-Z_\u7f-\uff][a-zA-Z0-9_\u7f-\uff]*)|(\()\s*(int|integer|bool|boolean|float|double|real|string|array|object|unset|binary)\s*(\))</expression>
				<!--static class method-->
				<capture number="1" name="variable.class" />
				<capture number="2" name="punctuation"/>
				<capture number="3" name="punctuation" />
				<capture number="4" name="variable.function.method.static" />
				<capture number="5" name="punctuation" />
				<capture number="6" name="punctuation.brace.round.open"/>
				<!-- static class property -->
				<capture number="7" name="variable.property.static" />
				<capture number="8" name="punctuation" />
				<!-- ->myFunction(); -->
				<capture number="9" name="punctuation.x-arrow"/>
				<capture number="10" name="variable.function.method" />
				<capture number="11" name="punctuation"/>
				<capture number="12" name="punctuation.brace.round.open" />
				<!-- ->property -->
				<capture number="13" name="variable.property"/>
				<capture number="14" name="punctuation"/>
				<!-- myFunction(); -->
				<capture number="15" name="variable.function" />
				<capture number="16" name="punctuation.brace.round.open" />
				<!--$this-->
				<capture number="17" name="keyword.variable.language"/>
				<capture number="18" name="punctuation" />
				<!--$argc and other predefined variables-->
				<capture number="19" name="keyword.variable.predefined"/>
				<capture number="20" name="punctuation"/>
				<!--$generic_variable-->
				<capture number="21" name="variable"/>
				<capture number="22" name="punctuation"/>
				<!--${$variable_variable}-->
				<capture number="23" name="variable"/>
				<capture number="24" name="punctuation"/>
				<capture number="25" name="expression.complex">
					<subzones>
						<include collection="strings" />
						<include collection="shell-executables" />
						<include collection="keywords" />
						<include collection="variables" />
						<include collection="punctuation" />
					</subzones>
				</capture>
				<capture number="26" name="punctuation"/>
				<!--constant-->
				<capture number="27" name="constant"/>
				<!-- Type casting -->
				<capture number="28" name="punctuation.brace.round.open"/>
				<capture number="29" name="keyword.typecast"/>
				<capture number="30" name="punctuation.brace.round.close"/>
			</zone>
		</collection>
		
		<!--Punctuation and operators-->
		<collection name="punctuation">
			<!-- FIXME: figure out if there's a better way to do this; it's necessary to group ternary operators into a sub-group in order to prevent the itemizers from getting confused about blocks with ternary statements in their parameters and the alternate `if () : ... endif;` formatting -->
			<zone name="x-ternary">
				<starts-with>
					<expression>\?</expression>
					<capture number="0" name="punctuation"/>
				</starts-with>
				<ends-with>
					<expression>:</expression>
					<capture number="0" name="punctuation"/>
				</ends-with>
				<subzones>
					<include collection="comments" />
					<include collection="strings" />
					<include collection="shell-executables" />
					<include collection="keywords" />
					<include collection="variables" />
					<include collection="punctuation" />
				</subzones>
			</zone>
			<zone>
				<expression>((?:\+|-|\*|/|%|\.|&lt;|>)=|=>|!={1,2}|={1,3}|&lt;>|\+{1,2}|-{1,2}|\*|/|%|\.|!|&lt;{1,2}|>{1,2}|&amp;{1,2}|\|{1,2}|\^|~|@)|(\()|(\))|(\{)|(\})|(\[)|(\])|(,|:|;)</expression>
				<capture number="1" name="operator"/>
				<capture number="2" name="punctuation.brace.round.open"/>
				<capture number="3" name="punctuation.brace.round.close"/>
				<capture number="4" name="punctuation.brace.curly.open"/>
				<capture number="5" name="punctuation.brace.curly.close"/>
				<capture number="6" name="punctuation.brace.square.open"/>
				<capture number="7" name="punctuation.brace.square.close"/>
				<capture number="8" name="punctuation" behavior="text-to-name" behavior-match="(,)|(:)|(;)" behavior-transform="x-(?1:comma:)(?2:colon:)(?3:semicolon:)" />
			</zone>
		</collection>
	</library>
</syntax>