动态添加行为扩展到某个标签
@param string $tag      标签行为
@param mixed  $behavior 标签行为
@param bool   $first    是否放到开头进行执行
517270
public static function add($tag, $behavior, $first = false)
    {
        if (!isset(self::$tags[$tag])) {
            self::$tags[$tag] = [];
        }

        if ($first) {
            array_unshift(self::$tags[$tag], $behavior);
        } else {
            self::$tags[$tag][] = $behavior;
        }
    }
486690
public function setFirst($first)
    {
        $this->_links[self::FIRST][self::HREF] = $first;
        $this->removeEmptyLinks();

        return $this;
    }
307982
public function createTag($tag, $message = null)
    {
        $command = 'tag';

        if ($message) {
            $command .= " -a -m '$message'";
        }

        $command .= " $tag";

        $this->getClient()->run($this, $command);
    }
851727
public function insert(WorkspaceTag $tag)
    {
        $this->om->persist($tag);
        $this->om->flush();
    }
713359
public function flushCachesByTag(string $tag, bool $flushPersistentCaches = false): void
    {
        $this->createAllCaches();
        /** @var FrontendInterface $cache */
        foreach ($this->caches as $identifier => $cache) {
            if (!$flushPersistentCaches && $this->isCachePersistent($identifier)) {
                continue;
            }
            $cache->flushByTag($tag);
        }
    }
320865
public function addToContext( string $key, $value, string $behavior ): View
    {
        switch ($behavior) {
            case View::REPLACE:
                $this->_context_[$key] = $value;
                return $this;
            case View::MERGE:
                if(array_key_exists($key, $this->_context_)) {
                    $this->_context_ = array_merge_recursive($this->_context_, [$key => $value]);
                    return $this;
                }
                $this->_context_[$key] = $value;
                return $this;
            case View::ADD_ONLY:
                if (array_key_exists($key, $this->_context_)) {
                    return $this;
                }
                $this->_context_[$key] = $value;
                return $this;
            case View::REPLACE_ONLY:
                if (! array_key_exists($key, $this->_context_)) {
                    return $this;
                }
                $this->_context_[$key] = $value;
                return $this;
            case View::MERGE_ONLY:
                if (! array_key_exists($key, $this->_context_)) {
                    return $this;
                }
                $this->_context_ = array_merge_recursive($this->_context_, [$key => $value]);
                return $this;
            default:
                throw new InvalidContextAddingBehavior(
                    sprintf(
                        _('Invalid behavior "%s" for adding to the context of view "%s".'),
                        $key,
                        $this->_uri_
                    )
                );
        }
    }
1072358
protected function processEndTag(Tag $tag)
	{
		$tagName = $tag->getName();

		if (empty($this->cntOpen[$tagName]))
		{
			// This is an end tag with no start tag
			return;
		}

		/**
		* @var array List of tags need to be closed before given tag
		*/
		$closeTags = [];

		// Iterate through all open tags from last to first to find a match for our tag
		$i = count($this->openTags);
		while (--$i >= 0)
		{
			$openTag = $this->openTags[$i];

			if ($tag->canClose($openTag))
			{
				break;
			}

			$closeTags[] = $openTag;
			++$this->currentFixingCost;
		}

		if ($i < 0)
		{
			// Did not find a matching tag
			$this->logger->debug('Skipping end tag with no start tag', ['tag' => $tag]);

			return;
		}

		// Accumulate flags to determine whether whitespace should be trimmed
		$flags = $tag->getFlags();
		foreach ($closeTags as $openTag)
		{
			$flags |= $openTag->getFlags();
		}
		$ignoreWhitespace = (bool) ($flags & self::RULE_IGNORE_WHITESPACE);

		// Only reopen tags if we haven't exceeded our "fixing" budget
		$keepReopening = (bool) ($this->currentFixingCost < $this->maxFixingCost);

		// Iterate over tags that are being closed, output their end tag and collect tags to be
		// reopened
		$reopenTags = [];
		foreach ($closeTags as $openTag)
		{
			$openTagName = $openTag->getName();

			// Test whether this tag should be reopened automatically
			if ($keepReopening)
			{
				if ($openTag->getFlags() & self::RULE_AUTO_REOPEN)
				{
					$reopenTags[] = $openTag;
				}
				else
				{
					$keepReopening = false;
				}
			}

			// Find the earliest position we can close this open tag
			$tagPos = $tag->getPos();
			if ($ignoreWhitespace)
			{
				$tagPos = $this->getMagicEndPos($tagPos);
			}

			// Output an end tag to close this start tag, then update the context
			$endTag = new Tag(Tag::END_TAG, $openTagName, $tagPos, 0);
			$endTag->setFlags($openTag->getFlags());
			$this->outputTag($endTag);
			$this->popContext();
		}

		// Output our tag, moving the cursor past it, then update the context
		$this->outputTag($tag);
		$this->popContext();

		// If our fixing budget allows it, peek at upcoming tags and remove end tags that would
		// close tags that are already being closed now. Also, filter our list of tags being
		// reopened by removing those that would immediately be closed
		if (!empty($closeTags) && $this->currentFixingCost < $this->maxFixingCost)
		{
			/**
			* @var integer Rightmost position of the portion of text to ignore
			*/
			$ignorePos = $this->pos;

			$i = count($this->tagStack);
			while (--$i >= 0 && ++$this->currentFixingCost < $this->maxFixingCost)
			{
				$upcomingTag = $this->tagStack[$i];

				// Test whether the upcoming tag is positioned at current "ignore" position and it's
				// strictly an end tag (not a start tag or a self-closing tag)
				if ($upcomingTag->getPos() > $ignorePos
				 || $upcomingTag->isStartTag())
				{
					break;
				}

				// Test whether this tag would close any of the tags we're about to reopen
				$j = count($closeTags);

				while (--$j >= 0 && ++$this->currentFixingCost < $this->maxFixingCost)
				{
					if ($upcomingTag->canClose($closeTags[$j]))
					{
						// Remove the tag from the lists and reset the keys
						array_splice($closeTags, $j, 1);

						if (isset($reopenTags[$j]))
						{
							array_splice($reopenTags, $j, 1);
						}

						// Extend the ignored text to cover this tag
						$ignorePos = max(
							$ignorePos,
							$upcomingTag->getPos() + $upcomingTag->getLen()
						);

						break;
					}
				}
			}

			if ($ignorePos > $this->pos)
			{
				/**
				* @todo have a method that takes (pos,len) rather than a Tag
				*/
				$this->outputIgnoreTag(new Tag(Tag::SELF_CLOSING_TAG, 'i', $this->pos, $ignorePos - $this->pos));
			}
		}

		// Re-add tags that need to be reopened, at current cursor position
		foreach ($reopenTags as $startTag)
		{
			$newTag = $this->addCopyTag($startTag, $this->pos, 0);

			// Re-pair the new tag
			$endTag = $startTag->getEndTag();
			if ($endTag)
			{
				$newTag->pairWith($endTag);
			}
		}
	}
1245782
public static function addDefaultOptions(Tag &$Tag)
    {
        if (isset(TagInfo::$defaultOptions[$Tag->name])) {
            foreach (TagInfo::$defaultOptions[$Tag->name] as $defopt) {
                if (!in_array($defopt, $Tag->options)) {
                    $Tag->options[] = $defopt;
                }
            }
        }
    }
402030
public static function onLoad(string $js, bool $first = false) {
		if (!$first) {
			self::$onload.= $js;
		} else {
			self::$onload_first.= $js;
		}
	}
160137
public function addTag($tag)
    {
        $tags = $this->getTags();
        array_push($tags, $tag);
        $this->setTags($tags);
    }
222883
public function mark($tag = NULL) {
        if (!\PhalApi\DI()->debug) {
            return;
        }

        $backTrace = debug_backtrace();
        if (empty($this->timeline)) {
            array_shift($backTrace);
        }
        // TODO 关于追踪，看下如何追踪更合适

        $this->timeline[] = array(
            'tag' => $tag, 
            'time' => $this->getCurMicroTime(),
            'file' => isset($backTrace[0]['file']) ? $backTrace[0]['file'] : '',
            'line' => isset($backTrace[0]['line']) ? $backTrace[0]['line'] : 0,
        );
    }
182683
public function tags_queue($tag_info = array(), $action = null)
    {

        if( ! isset($tag_info['item_id']) ) {
            throw new NoItemException("No item id was sent");
        } else if ( ! is_numeric($tag_info['item_id']) ){
            throw new InvalidItemTypeException("The item id: {$tag_info['item_id']} is not valid it should be a number");
        }

        if( sizeof($tag_info['tags']) == 0 ) {
            throw new NoItemException("No tags received");
        }
        
        $base_info  = array(
            'action'        => $action,
            'time'          => time()
        );

        $tag_info = array_merge($base_info, $tag_info);

        $this->actions[] = $tag_info;

        return true;

    }
1215211
public static function listen($tag, $params = null, $extra = null)
    {
        $result = true;

        if (isset(self::$tags[$tag])) {
            foreach (self::$tags[$tag] as $behaviors) {
                $result = self::exec($behaviors, $params, $extra);

                if ($result === false) {
                    return $result;
                }
            }
        }

        return $result;
    }
2848
protected function setEntityBehaviors($behaviors)
    {
        $this->entityLocalBehaviors = $behaviors;
        $cache = $this->getCache();
        if ($cache) {
            $tagDependencyConfig = ['tags' => [$this->getEntityBehaviorsCacheTag()]];
            $tagDependency = new TagDependency($tagDependencyConfig);
            $cache->set($this->getEntityBehaviorsCacheKey(), $behaviors, 0, $tagDependency);
        }
    }
395473
public function basic_nack($delivery_tag, $multiple = false, $requeue = false)
    {
        list($class_id, $method_id, $args) = $this->protocolWriter->basicNack($delivery_tag, $multiple, $requeue);
        $this->send_method_frame(array($class_id, $method_id), $args);
    }
204231
protected function verifyMustContain(&$actions, $mainTag, $mustTag)
    {
        $inMainTag = 0;
        $foundMustTag = false;

        foreach ($actions as $action) {
            if ($action->getName() == $mainTag && !$action->isClose()) {
                $inMainTag++;
                $foundMustTag = false;
            }

            if ($action->getName() == $mustTag && $inMainTag > 0) {
                $foundMustTag = true;
            }

            if ($action->getName() == $mainTag && $action->isClose()) {
                if (!$foundMustTag) {
                    $exception = new HtmlParsingException(
                        "The tag [$mainTag] must contain at least one tag [$mustTag]"
                    );
                    $exception->setInvalidTag($action->getName());
                    $exception->setHtmlLine($action->getLine());
                    throw $exception;
                }
                $inMainTag--;
            }
        }

        return true;
    }
1267823
public function publish($message, $tag = null)
    {
        $result = false;
        $request = new PublishMessageRequest($message, $tag);
        try {
            $res = $this->_topic->publishMessage($request);

            $result = $res->isSucceed();
        } catch (\Exception $e) {
            $this->eventsManager->fire('listener:logger', $this, '发送Topic消息失败：' . $e->getMessage());
        } finally {
            return $result;
        }
    }