final public function validate(callable $onDataInvalid = null): Validator {
        $shell = $this->shell;
        if (count($shell->subValidators)) {
            $shell->_safeVar = [];
            /**
             * @var Validator $validator
             * @var string    $key
             */
            foreach ($shell->subValidators as $key => $validator) {
                $validator->selfValidate();
                if ($validator->_isUndefined && $validator->onUndefinedIgnore) {
                    continue;
                }
                if ($validator->_isEmpty && $validator->onEmptyIgnore) {
                    continue;
                }
                if ($validator->_isValid) {
                    $shell->_safeVar[$key] = $validator->safeVar;
                } else if ($validator->message !== '') {
                    $shell->_messages[$key] = $validator->message;
                    $shell->_isValid = false;
                } else {
                    $shell->_messages[$key] = "$key is invalid";
                    $shell->_isValid = false;
                }
            }
            $shell->validated = true;
        } else {
            $this->selfValidate();
            if (!$this->_isValid) {
                $this->_messages[] = $this->message;
            }
        }
        if (!$shell->_isValid) {
            if (is_callable($onDataInvalid)) {
                $onDataInvalid($shell->messages, $shell);
            } else {
                throw new ValidatorException($shell->messages);
            }
        }

        return $shell;
    }